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:从子类到超类的一对一引用(Restaurant
到 Place
)
【讨论】:
难道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 模型继承和外键的主要内容,如果未能解决你的问题,请参考以下文章