Django Model Inheritance И Иностранные Ключи - PullRequest
11 голосов
/ 12 июля 2009

По сути, у меня есть модель, в которой я создал суперкласс, которым обладают многие другие классы, и затем у каждого из этих классов есть некоторые уникальные особенности, которые отличаются друг от друга. Допустим, класс A является суперклассом, а классы B, C и D являются потомками этого класса.

Как класс B, так и класс C могут иметь кратные классы D, однако я видел, что лучше поместить отношение внешнего ключа в класс D, который затем ссылается на его родительский класс. Теперь в других языках я мог бы просто сказать, что он имеет отношение ForeignKey к классу A, и тогда язык распознает истинный тип классов. Тем не менее, я не думаю, что так работает с Python.

Каков наилучший рекомендуемый способ решения этой проблемы?

РЕДАКТИРОВАТЬ: Вот примерно то, что я имею в виду ...

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 принадлежит только одному из них.

Ответы [ 4 ]

3 голосов
/ 23 октября 2010

Один из способов сделать это - добавить промежуточный класс следующим образом:

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 для получения дополнительной информации.

В вашей базе данных будут таблицы для Target, B, C и D, но не для A, поскольку они были помечены как абстрактные (вместо них в Target и D будут присутствовать столбцы, связанные с атрибутами в A).

[Предупреждение: я на самом деле не пробовал этот код - исправления приветствуются!]

3 голосов
/ 12 июля 2009

Из Django Docs :

Например, если вы строили База данных "мест", вы бы построить довольно стандартные вещи, такие как адрес, номер телефона и пр. в базе. Затем, если вы хотите построить База данных ресторанов на вершине места, вместо того, чтобы повторяться и реплицировать эти поля в Модель ресторана, вы могли бы сделать В ресторане есть OneToOneField для Место (потому что ресторан "это" место; на самом деле, чтобы справиться с этим, вы бы обычно используют наследование, которое включает в себя неявное один-к-одному отношение).

Обычно, вы бы просто Restaurant наследовали от Place. К сожалению, вам нужно то, что я считаю хаком: создание прямой ссылки от подкласса к суперклассу (Restaurant до Place)

3 голосов
/ 12 июля 2009

Вы также можете сделать общее отношение http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1 и проверить типы, чтобы ограничить его B или C при установке или сохранении. Это, вероятно, больше работы, чем выяснение прямой ссылки, но может показаться чище.

2 голосов
/ 12 июля 2009

Я вижу здесь проблему:

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(...)
...