TL;博士
对于在django中实现下面描述的基本数据模型模式,有没有一个简单的替代多表继承的方法?
前提
请考虑下图中非常基本的数据模型模式,例如:
Hay, 1996
.
简单地说:
Organizations
和
Persons
是
Parties
,以及所有
当事人
有
Address
锿。类似的模式可能适用于许多其他情况。
这里的重点是
是那个
地址
与
Party
,而不是与单个子模型的显式关系
Organization
和
Person
是的。
注意,每个子模型都引入了额外的字段(这里没有描述,但请参见下面的代码示例)。
这个具体的例子有几个明显的缺点,但那不是重点。为了便于讨论,假设模式完美地描述了我们希望实现的目标,那么剩下的唯一问题是
如何在django中实现该模式
是的。
实施
我相信,最明显的实现
multi-table-inheritance
以下内容:
class Party(models.Model):
""" Note this is a concrete model, not an abstract one. """
name = models.CharField(max_length=20)
class Organization(Party):
"""
Note that a one-to-one relation 'party_ptr' is automatically added,
and this is used as the primary key (the actual table has no 'id'
column). The same holds for Person.
"""
type = models.CharField(max_length=20)
class Person(Party):
favorite_color = models.CharField(max_length=20)
class Address(models.Model):
"""
Note that, because Party is a concrete model, rather than an abstract
one, we can reference it directly in a foreign key.
Since the Person and Organization models have one-to-one relations
with Party which act as primary key, we can conveniently create
Address objects setting either party=party_instance,
party=organization_instance, or party=person_instance.
"""
party = models.ForeignKey(to=Party, on_delete=models.CASCADE)
这似乎完全符合模式。这几乎让我相信这就是多表继承最初的目的。
但是,多表继承似乎是
frowned upon
,尤其是从性能的角度来看,尽管
it depends on the application
. 尤其是这个
scary, but ancient
,来自Django的一位创作者的帖子非常令人沮丧:
在几乎所有情况下,从长远来看,抽象继承都是一种更好的方法。我看到超过几个站点在具体继承带来的负载下崩溃,因此id强烈建议django用户对具体继承的任何使用持很大怀疑态度。
尽管有这个可怕的警告,我想这篇文章的要点是关于多表继承的以下观察:
这些连接往往是自动创建的“隐藏”的,这意味着看起来简单的查询通常不是这样的。
消歧
:上面的帖子将django的“多表继承”称为“具体继承”,不应将其与
Concrete Table Inheritance
在数据库级别。后者实际上更符合django使用抽象基类继承的概念。
我猜
this SO question
很好地说明了“隐藏连接”问题。
选择
抽象继承对我来说似乎不是一个可行的选择,因为我们不能为抽象模型设置外键,这是有意义的,因为它没有表。我想这意味着我们需要为每个“child”模型加上一些额外的逻辑来模拟这个过程。
代理继承看起来也不是一个选项,因为每个子模型都引入了额外的字段。
编辑:
再想一想,代理模型
能够
如果我们使用
Single Table Inheritance
在数据库级别,即使用一个包含
派对
,
组织
和
人
是的。
GenericForeignKey
关系可能是
some specific cases
但对我来说这是噩梦。
作为另一种选择,通常建议使用显式的一对一关系(
eoto公司
简而言之,这里)而不是多表继承(所以
聚会
我是说,
人
和
组织
都只是
models.Model
)中。
两种方法,多表继承(
MTI公司
)以及明确的一对一关系(
eoto公司
),生成三个数据库表。所以,
depending on the type of query, of course
,某种形式的
JOIN
在检索数据时经常是不可避免的。
通过检查数据库中的结果表,可以清楚地看到
MTI公司
和
eoto公司
在数据库级别,方法是
eoto公司
人
桌子有一个
id
列作为主键,另一个外键列作为
Party.id
,而
MTI公司
人
表有
不
分离
身份证件
列,但使用外键
参与方.id
作为它的主键。
问题
我不认为例子中的行为(特别是与父母的单一直接关系)可以通过
抽象继承
,可以吗如果它
可以
,那你怎么做到?
显式一对一关系是否真的比多表继承好得多,除了它迫使我们使查询更显式对我来说,多表方法的方便性和清晰性超过了显式论证。
注意
那个
this SO question
是非常相似的,但不完全回答我的问题。而且,最新的答案是
九年
现在已经很老了,从那以后django改变了很多。
[1]:
Hay 1996, Data Model Patterns