Django模型继承和外键

时间:2009-07-11 22:03:56

标签: python django inheritance django-models foreign-keys

基本上,我有一个模型,我创建了一个许多其他类共享的超类,然后每个类都有一些彼此不同的独特功能。假设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类只属于其中一个。

4 个答案:

答案 0 :(得分:3)

来自Django Docs

  

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

通常情况下,您只需Restaurant继承Place。遗憾的是,你需要我认为是黑客攻击:从子类到超类(RestaurantPlace)进行一对一的引用

答案 1 :(得分:3)

您还可以执行通用关系http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1,并在设置或保存时检查类型以将其约束为B或C.这可能比确定直接参考更有用,但可能会感觉更清洁。

答案 2 :(得分:3)

一种方法是按如下方式添加中间类:

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的链接。这有意义吗?有关详细信息,请参阅http://docs.djangoproject.com/en/1.2/topics/db/models/#model-inheritance

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

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

答案 3 :(得分:2)

我在这里看到一个问题:

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(...)