Наследование модели Django и внешние ключи
В принципе, у меня есть модель, где я создал суперкласс, который разделяют многие другие классы, а затем каждый из этих классов имеет некоторые уникальные функции, которые отличаются друг от друга. Пусть говорят, что класс A является суперклассом, а классы B, C и D являются дочерними элементами этого класса.
Оба класса B и класс C могут иметь кратность класса D, однако я видел, что лучше всего установить отношение внешнего ключа в классе D, которое затем относится к его родительскому классу. Теперь на других языках я могу просто сказать, что у него есть отношение ForeignKey к классу A, а затем язык распознает истинный тип классов. Однако я не думаю, что это работает с Python.
Какой лучший рекомендуемый способ решения этой проблемы?
EDIT: Вот примерно то, что я имею в виду...
class A(models.Model):
field = models.TextField()
class B(A):
other = <class specific functionality>
class C(A):
other2 = <different functionality>
class D(A):
#I would like class D to have a foreign key to either B or C, but not both.
По существу, класс B и класс C имеют несколько классов D. Но конкретный класс D принадлежит только одному из них.
Ответы
Ответ 1
Из Django Docs:
Например, если вы строили базы данных "мест", вы бы создали довольно стандартный материал, такой как адрес, номер телефона и т.д. в базе данных. Затем, если вы хотите создать база данных ресторанов на вершине места, а не повторять себя и тиражирование этих полей в Модель ресторана, вы можете сделать В ресторане есть OneToOneField для Место (потому что ресторан "является" место; на самом деле, чтобы справиться с этим, вы бы обычно используют наследование, которое подразумевает неявное взаимно однозначное отношение).
Обычно вы должны иметь Restaurant
наследовать от Place
. К сожалению, вам нужно, что я считаю взломом: создание взаимно однозначной ссылки из подкласса в суперкласс (Restaurant
to Place
)
Ответ 2
Вы также можете сделать общее отношение http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1 и проверить типы, чтобы ограничить его B или C при настройке или сохранении. Это, вероятно, больше работы, чем выяснение прямой ссылки, но может быть чище.
Ответ 3
Я вижу здесь проблему:
class D(A):
#D has foreign key to either B or C, but not both.
Невозможно это сделать. Вам придется добавить оба, потому что в столбцах SQL необходимо точно определить.
Кроме того, даже если унаследованные модели, например, вы компилируете с помощью syncdb
, они, похоже, не ведут себя так, как вы ожидали, по крайней мере, я не мог заставить их работать. Я не могу объяснить, почему.
Так работает FK в Django
class A(models.Model):
a = models.CharField(max_length=5)
class B(models.Model):
a = model.ForeignKey(A, related_name='A')
b = models.CharField(max_length=5)
class D(models.Model):
a = model.ForeignKey(A, related_name='A')
parent = model.ForeignKey(B, related_name='D')
таким образом вы можете эффективно иметь кратные D в B.
Наследование в моделях (например, класс B (A)) не работает, как я ожидал бы. Может быть, кто-то еще может объяснить это лучше.
Посмотрите этот документ. Это о взаимоотношениях "много-к-одному" в джанго.
b = B()
b.D_set.create(...)
Ответ 4
Один из способов сделать это - добавить промежуточный класс следующим образом:
class A(Model):
class Meta(Model.Meta):
abstract = True
# common definitions here
class Target(A):
# this is the target for links from D - you then need to access the
# subclass through ".b" or ".c"
# (no fields here)
class B(Target):
# additional fields here
class C(Target):
# additional fields here
class D(A):
b_or_c = ForeignKey(Target)
def resolve_target(self):
# this does the work for you in testing for whether it is linked
# to a b or c instance
try:
return self.b_or_c.b
except B.DoesNotExist:
return self.b_or_c.c
Использование промежуточного класса (Target) гарантирует, что будет только одна ссылка из D на B или C. Имеет ли это смысл? Подробнее см. http://docs.djangoproject.com/en/1.2/topics/db/models/#model-inheritance.
В вашей базе данных будут таблицы для целей, B, C и D, но не A, потому что это было отмечено как абстрактное (вместо этого столбцы, связанные с атрибутами на A, будут присутствовать в Target и D).
[Warning: Я действительно не пробовал этот код - любые исправления приветствуются!]