создание моделей с необязательной связью Django
как мне сделать такую связь как на картинке. Немного поясню. Есть определенный классы, в зависимости от того какой это класс, унего может быть(или не быть) подкласс. ЕСли подкласс есть, то от него идет связь к порядку, если подкласса нет, но связь идет сразу от класса к порядку. Я сделал так: (но не совсем уверен что это правильно)
class Class_plants(models.Model):
name_class = models.CharField('название класса', max_length = 50)
class_description = models.TextField('описание класса')
slug = models.SlugField(unique=True, null=True, blank=True)
department = models.ForeignKey(Departments,on_delete=models.CASCADE, verbose_name='отдел', related_name='dep')
def __str__(self):
return self.name_class
def save(self, *args, **kwargs):
self.slug = slugify(self.name_class)
return super(Class_plants, self).save(*args, **kwargs)
class Meta:
verbose_name = 'Класс'
verbose_name_plural = 'Классы'
class Subclass_plants(models.Model):
name_subclass = models.CharField('название подкласса', max_length = 50)
subclass_description = models.TextField('описание подкласса')
slug = models.SlugField(unique=True, null=True, blank=True)
class_plant = models.ForeignKey(Class_plants,on_delete=models.CASCADE,verbose_name='класс',related_name='clas',
null = True, blank = True)
def __str__(self):
return self.name_subclass
def save(self, *args, **kwargs):
self.slug = slugify(self.name_subclass)
return super(Subclass_plants, self).save(*args, **kwargs)
class Meta:
verbose_name = 'Подкласс'
verbose_name_plural = 'Подклассы'
class Orders_plants(models.Model):
name_orders = models.CharField('название порядка',max_length = 50)
orders_description = models.TextField('описанние порядка')
slug = models.SlugField(unique=True, null=True, blank=True)
class_plant = models.ForeignKey(Class_plants,on_delete=models.CASCADE,verbose_name='класс',related_name='class_plant_order',
null = True, blank = True)
sub_class_plant = models.ForeignKey(Subclass_plants,on_delete=models.CASCADE,verbose_name='подкласс',related_name='subclass',
null = True, blank = True)
def __str__(self):
return self.name_orders
def save(self, *args, **kwargs):
self.slug = slugify(self.name_orders)
return super(Orders_plants, self).save(*args, **kwargs)
class Meta:
verbose_name = 'Порядок'
verbose_name_plural = 'Порядки'
Подскажите правильно ли я записал модели?

Ответы (1 шт):
Я бы предложил создать один программный класс на все таксономические категории, их конкретный ранг хранить в каждом конкретном объекте в виде отдельного поля, а валидность отношений проверять дополнительной логикой. Например, вот так:
from django.db import models
RANK_CF = 3
def generate_ranks():
RANKS = [
'Life', 'Domain', 'Kindom', 'Phylum', 'Class',
'Order', 'Family', 'Genus', 'Species',
]
Rank2ind = {}
Ind2rank = {}
RankChoices = []
def add(name, index):
Rank2ind[name] = index
Ind2rank[index] = name
RankChoices.append((index, name))
for i, name in RANKS.enumerate():
# У каждого таксона из списка будет свой индекс
# по заданной формуле, а также версии над-/под-
# Например, таксон класс Class имеет индекс 13
# а надкласс 12, подкласс 14
index = 1 + i * RANK_CF
add(name, index)
add('Sub' + name, index - 1)
add('Infra' + name, index + 1)
return Rank2ind, Ind2rank, RankChoices
def validate_ranks(lower, upper):
diff = lower.rank - lower.upper.rank
# Валидным расстояннием считается разность от 1 до 3
# То есть, между смежными таксонами и их над-/под- версими
if diff > RANK_CF or diff < 1:
raise ValueError(
f'Taxon {upper} cannot be'
f' upper of {lower}, diff={diff}'
)
Rank2ind, Ind2rank, RankChoices = generate_ranks()
class Taxon(models.Model):
upper = models.ForeignKey(
'self', related_name='lower',
on_delete=models.PROTECT, null=True, blank=True)
title = models.CharField(max_length=255)
rank = models.IntegerField(choices=RankChoices)
def save(self, *args, **kwargs):
# Проверить корректность верхнего таксона
if self.upper:
validate_ranks(self, self.upper)
# Вызвать родительский метод для сохранения объекта
super().save(*args, **kwargs)
def __str__(self):
return repr(self)
def __repr__(self):
return f'{self.pk}. {self.rank} "{self.title}"'
Вероятно это не идеальная версия, т.к я не разбираюсь в биологической систематике (как минимум, кажется не у всех таксонов есть над/под версии), и можно придумать немного другую, более точную систему рангов и их отношений, например задать хранить как граф возможных отношений представленного в виде матрицы смежности, и возможно хранить в самой БД лучше как строки, а не числа... В общем, смотрите сами с учётом нюансов из предметной области и проекта, вариант для вдохновения я задал :)