django多重继承

时间:2012-08-22 13:08:02

标签: django django-models django-inheritance

我目前正在开发一个django项目,我需要做多个遗产。它自己的项目有一个管理员与多个网站。在我的管理部分,我创建了一个包含成员所有必填信息的成员类。然后,所有单个站点都有一个MemberExtra类,该类是从admin中的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")

programsite / 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)

2 个答案:

答案 0 :(得分:2)

这里的问题是你继承了你的模型两次,并且两个子模型都有相同的名称。这导致两次相同的related_name,这对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实际上创建了一个OneToOneFieldhttps://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance)。 在这种情况下,此字段称为<parentclass>_ptrmember_ptr

<击> 如果你手动创建一个名为OneToOneField的{​​{1}},并给它一个related_name,Django仍然可以找到父模型,并且不会抱怨相同的related_names。

<罢工>

在您的情况下,只需添加

<parentclass>_ptr
<{1}}模型定义中的

此解决方案有效,但不是应该如何完成。 Django提供了一个标志member_ptr = models.OneToOneField(Member, related_name="%(app_label)s_%(class)s_related")" ,当设置为true时,将告诉Django这是用于访问父类的字段。

所以你可以添加一个字段

MemberExtra

如果由于某种原因,Django需要将默认指针重命名为父级,那么它仍然可以工作。

答案 1 :(得分:1)

FK的related_name必须是唯一的。如果您的FK具有默认related_name(未指定),并且由多个其他模型继承,则所有模型最终都具有相同的related_name。请参阅名为Be careful with related_name的Django文档中的部分。

解决方案是将FK的related_name参数设置为:

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

Django然后将app标签和模块名称转换为字符串,使每个子类的related_name唯一。