【问题标题】:Django inheritance and parent object related nameDjango继承和父对象相关名称
【发布时间】:2017-03-13 14:22:02
【问题描述】:

我正在将一个项目从 django 1.8 升级到 1.10,看起来 django 改进了外键和模型继承之间最终名称冲突的检查。 这显然是一件好事,但我需要升级的项目很大,重命名一个模型将是一个地狱。

让我解释一下问题:我有一个名为Parent 的基类和许多链接在一起的子类,就像这样:

class Parent(models.Model):
    title = models.CharField(max_length=10)


class ChildA(Parent):
    description = models.TextField()


class ChildB(Parent):
    description = models.TextField()
    childa = models.ForeignKey(ChildA)

这里的冲突是childb 对象有 2 个“childa”属性:

  • “childa”外键
  • ChildA 模型继承的实例(因为 childb 也有 parent 属性)。

这里有两个明显的解决方案:

  • 将 ForeignKey ChildB.childa 重命名为 ChildB.somethingelse
  • ChildA 模型重命名为其他名称。

这两种解决方案的成本都很高,并且可能会引入新的错误。 所以我想知道:是否可以重命名继承对象的反向相关名称?

例如:

p = Parent.objects.get(pk=1)
print p.childa_child  # Hit the ChildA instance

我不知道我是否足够清楚,但我会及时更新这个问题。

==== 编辑 ====

为了更简洁,如果我有两个模型class Parent(models.Model)class Child(Parent),则会创建一个动态属性parent.child

是否可以在不触及类名的情况下编辑此属性名?

【问题讨论】:

    标签: python django inheritance


    【解决方案1】:

    多表继承在基本模型和子类之间创建了一个隐式OneToOneField 字段。

    Django 允许您通过显式设置一对一字段来修改这种关系。

    class Parent(models.Model):
        title = models.CharField(max_length=10)
    
    
    class ChildA(Parent):
        parent = models.OneToOneField(to=Parent, parent_link=True)
        description = models.TextField()
    
    
    class ChildB(Parent):
        parent = models.OneToOneField(to=Parent, parent_link=True)
        description = models.TextField()
        childa = models.ForeignKey(ChildA)
    

    这里的重要一点是 parent_link=True 参数,它告诉 Django 使用此字段声明来管理这两个模型的多表继承。

    因此,您现在可以设置 related_name='+' 以防止 Django 创建反向关系,或者您可以将 related_name 设置为更独特的名称:

    class ChildA(Parent):
        parent = models.OneToOneField(to=Parent, parent_link=True, related_name='child_a_here')
        description = models.TextField()
    
    
    class ChildB(Parent):
        parent = models.OneToOneField(to=Parent, parent_link=True, related_name='child_b_here')
        description = models.TextField()
        childa = models.ForeignKey(ChildA)
    

    【讨论】:

    • 就是这样!谢谢你。这里也是文档中参考的链接:docs.djangoproject.com/en/1.10/topics/db/models/…
    • 工作,特别是对于遗留修复,您需要命名父链接 [小写类名]_ptr 以模仿 1.8 行为,例如: parent_ptr = models.OneToOneField(to=Parent, parent_link=True, related_name='+'),它使用数据库字段 parent_ptr_id,就像 1.8 版一样。
    【解决方案2】:

    我有点困惑 ChildB 如何与两个 ChildA 链接,看起来您可能从模型中遗漏了一些关系字段?无论如何,我认为您正在寻找的是 related_name 参数。

    所以:

    class ChildB(Parent):
        description = models.TextField()
        childa = models.ForeignKey(ChildA, related_name='b_children')
    

    你可以这样查询:

    a = ChildA.objects.get(id=1)
    print(a.b_children)
    

    您可能还对abstract models感兴趣。

    【讨论】:

    • 感谢您的回答。这不是问题。我找到了与这一点相关的 django 票证:code.djangoproject.com/ticket/17673 Parent 模型有 2 个属性“childa”,在 django 1.8 之前,它被承认是其中一个属性的影子,但是使用 django 1.9+ 它会引发 SystemCheckError。 p = Parent.objects.get(pk=1) print p.childa # 应该命中 ChildA 孩子还是 ChildB 孩子的 childa 属性?
    • 我已经编辑了最初的帖子以添加一个更简单的示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多