Django模型继承和外键

问题描述 投票:11回答:4

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

python django inheritance django-models foreign-keys
4个回答
3
投票

Django Docs

例如,如果您要构建一个“地方”的数据库,您将建立非常标准的东西,例如地址,数据库中的电话号码等。然后,如果您想建立一个顶部的餐厅数据库的地方,而不是重复自己并将这些字段复制到餐厅模型,您可以制作餐厅有一个OneToOneField地点(因为餐厅“是”地点;实际上,要解决这个问题通常使用继承,涉及隐式一对一关系)。

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


3
投票

您也可以进行一般关系http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1,并在设置或保存时检查类型以将其限制为B或C。这可能比找出直接参考要花的功夫更多,但可能会感觉更干净。


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

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

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

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


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(...)
© www.soinside.com 2019 - 2024. All rights reserved.