Django模型继承与外键

13 投票
4 回答
13506 浏览
提问于 2025-04-15 12:50

基本上,我有一个模型,里面创建了一个父类,很多其他类都共享这个父类。然后每个子类都有一些独特的特点,彼此之间有所不同。比如说,类 A 是父类,而类 B、C 和 D 是这个类的子类。

类 B 和类 C 都可以有多个类 D,但我发现把外键关系放在类 D 中是最好的,这样类 D 就可以指向它的父类。其他编程语言中,我可以简单地说类 D 有一个指向类 A 的外键关系,然后语言就能识别这些类的真实类型。不过,我觉得在 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 只属于其中一个。

4 个回答

4

你也可以使用一种通用关系,具体可以参考这个链接:http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1。在设置或保存的时候,可以检查类型来限制它只能是B或C。这种方法可能比直接引用要复杂一些,但可能会让代码看起来更整洁。

6

一种实现这个目标的方法是添加一个中间类,像这样:

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被标记为抽象类(相反,A相关的属性列会出现在Target和D中)。

[警告:我实际上没有试过这段代码,欢迎任何纠正!]

3

来自Django 文档

举个例子,如果你在建立一个“地点”的数据库,你会在数据库里放一些比较常见的信息,比如地址、电话号码等等。然后,如果你想在这个地点的基础上建立一个餐厅的数据库,避免重复输入这些信息,你可以让餐厅模型(Restaurant)和地点模型(Place)之间建立一个一对一的关系。因为餐厅本身就是一个地点;实际上,处理这种关系时,通常会用到继承,这样就会隐含地形成一对一的关系。

通常情况下,你会让Restaurant直接继承Place。可惜的是,这里你需要用到我认为有点“hack”的方法:让子类(Restaurant)和父类(Place)之间建立一个一对一的引用。

撰写回答