Джанго множественное наследование

В настоящее время я работаю над проектом django, где мне нужно сделать несколько наследий. Сам по себе проект имеет администратора с несколькими веб-сайтами. В моей административной части я создал класс Member, содержащий всю обязательную информацию для члена. Затем все отдельные сайты имеют класс MemberExtra, созданный из класса Member от администратора, куда я добавляю всю дополнительную информацию. Когда я запускаю свой сервер (python manage.py runserver...), у меня возникает эта ошибка:

Error: One or more models did not validate:
programsite.memberextra: Accessor for field 'member_ptr' clashes with related field 'Member.memberextra'. Add a related_name argument to the definition for 'member_ptr'.
programsite.memberextra: Reverse query name for field 'member_ptr' clashes with related field 'Member.memberextra'. Add a related_name argument to the definition for 'member_ptr'.
gourmandiz.memberextra: Accessor for field 'member_ptr' clashes with related field 'Member.memberextra'. Add a related_name argument to the definition for 'member_ptr'.
gourmandiz.memberextra: Reverse query name for field 'member_ptr' clashes with related field 'Member.memberextra'. Add a related_name argument to the definition for 'member_ptr'.

админ/models.py:

class Member(models.Model):
    prog = models.ForeignKey(Program, verbose_name=_("Program"))
    status = models.CharField(_("Status"), m    status = models.CharField(_("Status"), max_length=1, choices=STATUS_CHOICE\
S)
    points_avai = models.BigIntegerField(_("
Current Points"), null=True)
    points_notavai = models.BigIntegerField(_("Future Points"), null=True)
    cn = models.CharField(_("Company name"), max_length=250)
    full_name = models.CharField(_("Full name"), max_length=250)
    b_add = models.CharField(_("Billing address"), max_length=250)
    b_city = models.CharField(_("Billing City"), max_length=250)
    b_zip = models.CharField(_("Billing ZIP code"), max_length=250)
    b_country = models.CharField(_("Billing country"), max_length=250)
    prog_start_date = models.DateField(_("Program start date"), null=True)
    prog_end_date = models.DateField(_("Program end date"), null=True)
    member_id = models.CharField(_("Member ID"), max_length=250, primary_key=T\
rue)
    client_id = models.CharField(_("Client ID"), max_length=250, help_text="Nu\
méro de client.")
    user = models.OneToOneField(User)

    def __unicode__(self):
        return self.full_name + " (" + str(self.member_id) + ")"

    class Meta:                                                     
        verbose_name = _("Member")
        verbose_name_plural = _("Members")

сайт программы/models.py:

class MemberExtra(Member):
 email = models.EmailField(_("Email"), max_length=100, null=True)
 tel = models.CharField(_("Tel"), max_length=100, null=True)
 patrick = models.CharField(_("Patrick"), max_length=100, null=True)
 test42 = models.CharField(_("Test42"), max_length=100, null=True)

gourmandiz/models.py:

class MemberExtra(Member):
     email = models.EmailField(_("Email"), max_length=100, null=True)

person BiG-Up    schedule 22.08.2012    source источник


Ответы (2)


Проблема здесь в том, что вы наследуете свою модель дважды, и обе дочерние модели имеют одно и то же имя. Это приводит к тому, что у вас будет дважды одно и то же связанное_имя, что является проблемой для Django.

Ваше решение добавить

member = models.OneToOneField(Member, related_name="%(app_label)s_%(class)s_related")"

в вашей модели MemberExtra работает, но вы теряете магию неявного наследования, которую делает Django, чтобы вы могли получить доступ к обеим вашим моделям в одной:

С вашим решением вы должны сделать:

from programsite.models import MemberExtra
m = MemberExtra.objects.get(member__full_name = "Foobar")
m.email # -> returns the email of your MemberExtra instance
m.member.b_add # -> returns the address of the inherited member instance

Где с собственным наследованием Django вы можете сделать:

from programsite.models import MemberExtra
m = MemberExtra.objects.get(full_name = "Foobar")
m.email # -> returns the email of your MemberExtra instance
m.b_add # -> returns the address of the inherited member instance

Что, на мой взгляд, намного чище.

Для управления наследованием Django фактически создает OneToOneField (https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance). Это поле называется <parentclass>_ptr, в вашем случае member_ptr.

Если вы вручную создадите OneToOneField с именем <parentclass>_ptr и дадите ему связанное_имя, Django по-прежнему сможет найти родительскую модель и не будет жаловаться на идентичные связанные_имена.

В вашем случае просто добавьте

member_ptr = models.OneToOneField(Member, related_name="%(app_label)s_%(class)s_related")"

в обоих определениях модели MemberExtra.

Это решение работает, но это не то, как это должно быть сделано. Django предоставляет флаг parent_link, который, если установлено значение true, сообщает Django, что это поле будет использоваться для доступа к родительскому классу.

Таким образом, вы можете добавить поле

member = models.OneToOneField(Member, parent_link=True, related_name="%(app_label)s_%(class)s_related")"

который по-прежнему будет работать, если по какой-то причине Django потребуется переименовать указатель по умолчанию на родительский.

person Thierry J.    schedule 07.05.2013

related_name для FK должен быть уникальным. Если у вас есть FK со значением по умолчанию related_name (не указано), которое унаследовано несколькими другими моделями, все модели получат один и тот же related_name. См. раздел документации Django под названием Будьте осторожны с related_name.

Решение состоит в том, чтобы установить аргумент related_name FK примерно так:

prog = models.ForeignKey(Program, verbose_name=_("Program"), related_name="%(app_label)s_%(class)s_related")

Затем Django подставит метку приложения и имя модуля в строку, сделав related_name уникальным для каждого из подклассов.

person Chris Pratt    schedule 22.08.2012
comment
Я решил свою проблему, я добавил member = models.OneToOneField(Member, related_name=%(app_label)s_%(class)s_related) в мой MemberExtra. - person BiG-Up; 23.08.2012