Поле модели Django с несколькими типами?

#django #django-models

#django #django-модели

Вопрос:

У меня есть следующие (упрощенные) модели:

 class Structure(models.Model):
name=models.CharField(max_length=100, unique=True)

class Unit(models.Model):
name=models.CharField(max_length=100, unique=True)
  

Каждая модель также имеет поле builtFrom, которое показывает, из чего построен элемент, например:

 class Unit(models.Model):
name=models.CharField(max_length=100, unique=True)
builtFrom=models.ForeignKey(Structure)
  

Однако builtFrom может быть заполнен либо из типа Unit, либо из типа Structure. Есть ли простой способ представить это в моих моделях?

Единственное, о чем я могу думать, это иметь отдельную модель, вот так:

 class BuiltFromItem(models.Model):
structure=models.ForeignKey(Structure)
unit=models.ForeignKey(Structure)


class Unit(models.Model):
name=models.CharField(max_length=100, unique=True)
builtFrom=models.ForeignKey(BuiltFromItem)
  

И тогда пусть одно из полей BuiltFromItem просто будет null. Затем, когда мне понадобятся данные, выясните, является ли это структурой или блоком, из которого они построены. Есть ли лучшее решение для этого?

Ответ №1:

Вы хотите то, что в документах Django называется «общим отношением«. Поддержка для них встроена в Django.

Комментарии:

1. Ссылка не работает, вот новая ссылка.

Ответ №2:

Вероятно, наилучшим подходом является универсальное отношение, но это может быть немного проблематично, если вы планируете управлять такими моделями через панель администратора. Затем вам пришлось бы добавить ModelInline к моделям, на которые указывает общее отношение, но, насколько я знаю (поправьте меня, если я ошибаюсь), нет удобного способа выбрать связанный объект с другой стороны (из модели, где определено отношение), кроме выбора класса модели и ручного ввода первичного ключа экземпляра.

Выбор наилучшего решения на самом деле зависит от структуры ваших моделей и от того, что у них общего. Другая идея, которая у меня есть, заключается в использовании многостолового наследования, путем определения некоторого BasicObject родительского объекта для Structure и Unit моделей:

 class BasicObject(models.Model):
    name=models.CharField(max_length=100, unique=True)
    #other common data
    builtFrom=models.ForeignKey('BasicObject')

class Structure(BasicObject):
    #data specific to Structure

class Unit(BasicObject):
    #data specific to Unit
  

Теперь все Structure и Unit object также будут BasicObject экземплярами, и вы сможете заполнить builtFrom поле соответствующим BasicObject экземпляром. Это удорожает запросы, поскольку данные разделяются на две разные таблицы, поэтому вам следует подумать, выгоден ли этот подход в вашем случае.