Django模型继承和外键

13

我有一个模型,其中创建了一个父类,许多其他类都共享该父类,每个子类都具有一些独特的特征与其他类不同。假设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只属于其中一个。


你能解释一下为什么需要继承吗? - Evgeny
这里有一个相关的问题,其中有一些不错的答案可能会有所帮助:https://dev59.com/T3NA5IYBdhLWcg3wC5NR - Mzq
4个回答

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

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

使用中间类(Target)可以确保D只与B或C有一个连接。这样说通了吗?详见模型继承获取更多信息。
在您的数据库中,将会有Target、B、C和D表格,但没有A表格,因为它被标记为抽象的(相反,与A属性相关的列将存在于Target和D中)。
[警告:我并没有实际尝试这段代码-欢迎任何纠正!]

是的,这似乎是一个可行的解决方案。具体继承肯定是一种途径。GenericForeignKey是另一种方法。两者都有其优缺点。例如,使用具体继承,您可以在同一查询中列出C和D。但是,您需要执行许多左连接并且必须合并任何值。GenericForeignKey是另一种相当直观和易读的解决方案,但我总是后悔使用它们。就此打住。 - natehawkboss

4

3

来自Django文档:

例如,如果您正在构建一个“地点”数据库,您将在数据库中构建非常标准的内容,如地址,电话号码等。然后,如果您想在“地点”的基础上构建餐厅数据库,而不是重复自己并在餐厅模型中复制那些字段,您可以使餐厅具有对“地点”的OneToOneField引用(因为餐厅“是”地点; 实际上,为了处理这个问题,您通常会使用继承,其中涉及隐式一对一关系)。

通常,您只需使RestaurantPlace继承即可。遗憾的是,您需要我认为是一种技巧:从子类到超类(RestaurantPlace)进行一对一引用。


Django 默认提供这样的一对一引用吗?例如,对于多表继承模型,“restaurant.place”返回相应的 Place 实例,无需用户定义除继承之外的任何关系。 - Jonathan Hartley
3
也许现在是这样,但我认为在2009年不是这样。 - geowa4

2
我发现这里有一个问题:
class D(A):
    #D has foreign key to either B or C, but not both.

无法这样做。因为在SQL中,列必须被精确定义,所以您需要添加两个。

此外,即使像您这样的继承模型通过syncdb编译,它们似乎并不像您期望的那样运行 - 至少我无法让它们工作。我无法解释原因。

以下是Django中FK的工作方式。

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。
模型中的继承(例如class B(A))并不像我期望的那样工作。也许其他人能更好地解释它。
请看这个文档页面:这里。它是关于Django中多对一关系的。
b = B()
b.D_set.create(...)

1
我的问题是,我希望类D属于类A或类B中的一个,而不是两个都属于。我会在我的问题中澄清。 - AlbertoPL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接