【问题标题】:django multiple inheritancedjango 多重继承
【发布时间】:2012-08-22 13:08:02
【问题描述】:

我目前正在开发一个 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")

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)

【问题讨论】:

    标签: django django-models django-inheritance


    【解决方案1】:

    这里的问题是您继承了您的模型两次,并且两个子模型具有相同的名称。这会导致两个相同的相关名称,这对 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>_ptrmember_ptr

    如果你手动创建一个名为<parentclass>_ptrOneToOneField,并给它一个related_name,Django 仍然能够找到父模型,并且不会抱怨相同的related_names。

    在你的情况下,只需添加

    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 需要重命名指向父级的默认指针,它仍然可以工作。

    【讨论】:

      【解决方案2】:

      FK 的related_name 必须是唯一的。当您有一个具有默认 related_name(未指定)的 FK 时,该 FK 被多个其他模型继承,所有模型最终都具有相同的 related_name。请参阅 Django 文档中标题为 Be careful with related_name 的部分。

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

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

      然后,Django 会将应用标签和模块名称分到字符串中,使 related_name 对于每个子类都是唯一的。

      【讨论】:

      • 我解决了我的问题,我在“MemberExtra”中添加了“member = models.OneToOneField(Member,related_name="%(app_label)s_%(class)s_related")”。
      猜你喜欢
      • 2015-09-16
      • 1970-01-01
      • 2012-03-08
      • 1970-01-01
      • 2017-10-14
      • 2010-09-27
      • 2012-03-07
      相关资源
      最近更新 更多