Django 模型继承和外键

Posted

技术标签:

【中文标题】Django 模型继承和外键【英文标题】:Django Model Inheritance And Foreign Keys 【发布时间】:2010-11-10 00:42:00 【问题描述】:

基本上,我有一个模型,其中我创建了许多其他类共享的超类,然后这些类中的每一个都有一些彼此不同的独特功能。假设 A 类是超类,B、C 和 D 类是该类的子类。

B 类和 C 类都可以有 D 类的倍数,但是我发现最好将外键关系放在 D 类中,然后它引用它的父类。现在在其他语言中,我可以简单地说它与 A 类有 ForeignKey 关系,然后该语言会识别类的真实类型。但是,我不认为 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 类只属于其中一个。

【问题讨论】:

您能解释一下为什么需要继承吗? 有一个相关的问题有一些不错的答案可能会有所帮助:***.com/questions/1114767/… 【参考方案1】:

您也可以做一个通用关系http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1 并检查类型以在设置或保存时将其限制为 B 或 C。这可能比找出直接引用需要更多的工作,但可能感觉更简洁。

【讨论】:

【参考方案2】:

一种方法是添加一个中间类,如下所示:

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

使用中间类(目标)保证从 D 到 B 或 C 的链接只有一个。这有意义吗?请参阅model inheritance 了解更多信息。

在您的数据库中,将有 Target、B、C 和 D 的表,但没有 A,因为它被标记为抽象(相反,与 A 上的属性相关的列将出现在 Target 和 D 中)。

[警告:我还没有实际尝试过这段代码 - 欢迎任何更正!]

【讨论】:

【参考方案3】:

来自Django Docs:

例如,如果您正在构建一个 “地方”的数据库,你会建立 非常标准的东西,例如地址, 数据库中的电话号码等。 那么,如果你想建立一个 餐厅数据库 地方,而不是重复自己 并在 餐厅模型,你可以做 餐厅有一个OneToOneField 地方(因为餐厅“是” 地方;事实上,要处理这个问题,你会 通常使用继承,即 涉及隐含的一对一 关系)。

通常,您只需让 Restaurant 继承自 Place。可悲的是,您需要我认为的 hack:从子类到超类的一对一引用(RestaurantPlace

【讨论】:

难道django默认不提供这种一对一的引用吗?例如对于多表继承模型,“restaurant.place”返回对应的Place实例,不需要用户定义继承以外的任何关系。 现在可能有,但我认为 2009 中没有。【参考方案4】:

我在这里看到一个问题:

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')

这样你就可以有效地在 B 中拥有 D 的倍数。

模型中的继承(例如 B(A) 类)无法正常工作。也许其他人可以更好地解释它。

看看this doc 页面。这是关于 django 中的多对一关系。

b = B()
b.D_set.create(...)

【讨论】:

我的问题是,我希望 D 类属于 A 类或 B 类,而不是两者。我会在我的问题中澄清。

以上是关于Django 模型继承和外键的主要内容,如果未能解决你的问题,请参考以下文章

Symfony/Doctrine 类表继承和外键作为主键

Django 中的抽象模型和外键

如何在Django中加入非主键和外键列的查询

一对一和外键关系之间的区别?

Django - 来自抽象基类的外键[重复]

Grails 域模型中的继承导致重复的外键