Django 中是否明确支持单表继承? 据我所知,该功能仍在开发和争论中。
是否有我可以同时使用的库/黑客来捕获基本行为? 我有一个混合不同对象的层次结构。 具有 Employee 类、员工类型的子类和 manager_id (parent_id) 的公司结构的典型示例将是我正在解决的问题的一个很好的近似。
就我而言,我想表达这样一种想法:一名员工可以在被另一名员工管理的同时管理其他员工。 Manager 和 Worker 没有单独的类,这使得它很难跨表传播。 子类将代表员工的类型——程序员、会计师、销售人员等,并且独立于谁监督谁(好吧,我想在某些方面它不再是一个典型的公司)。
Is there explicit support for Single Table Inheritance in Django? Last I heard, the feature was still under development and debate.
Are there libraries/hacks I can use in the meantime to capture the basic behavior? I have a hierarchy that mixes different objects. The canonical example of a corporation structure with an Employee class, subclasses for types of employees, and a manager_id (parent_id) would be a good approximation of the problem I am solving.
In my case, I would like to represent the idea that an employee can manage other employees while being managed by a different employee. There are not separate classes for Manager and Worker, which makes this hard to spread across tables. Sub-classes would represent types of employees-programmers, accountants, sales, etc and would be independent of who supervises who (OK, I guess it's no longer a typical corporation in some respect).
发布评论
评论(6)
摘要
Django 的 代理模型 为单表提供了基础遗产。
然而,需要付出一些努力才能使其发挥作用。
跳到最后查看可重复使用的示例。
背景
Martin Fowler 对单表继承 (STI) 的描述如下:
这正是 Django 的代理模型继承所做的。
请注意,根据这篇 2010 年的博客文章,
代理
模型自 Django 1.1 以来就已经存在。“普通”Django 模型是一个具体模型,即它在数据库中有一个专用表。
有两种类型的 Django 模型没有有专用的数据库表,即。 抽象模型和代理模型:
抽象模型充当具体模型的超类。 抽象模型可以定义字段,但它没有数据库表。 这些字段仅添加到其具体子类的数据库表中。
代理模型充当具体模型的子类。 代理模型无法定义新字段。 相反,它对与其具体超类关联的数据库表进行操作。 换句话说,Django 具体模型及其代理都共享一个表。
Django 的代理模型为单表继承提供了基础,即。 它们允许不同的模型共享一个表,并且允许我们在 Python 端定义特定于代理的行为。 但是,Django 的默认对象关系映射 (ORM) 并未提供预期的所有行为,因此需要进行一些自定义。 多少,这取决于你的需求。
让我们基于下图中的简单数据模型逐步构建一个最小的示例:
第 1 步:基本“代理模型继承”
这是
models.py 用于基本代理继承实现:
Person
和Organization
是两种类型的参与方。只有
Party
模型具有数据库表,因此所有字段都在此模型上定义,包括特定于Person
或到组织
。由于
Party
、Person
和Organization
都使用Party
数据库表,因此我们可以定义单个将ForeignKey
字段分配给Party
,并将三个模型中任意一个的实例分配给该字段,如图中的继承关系所示。 请注意,如果没有继承,我们将需要为每个模型提供一个单独的ForeignKey
字段。例如,假设我们定义一个
Address
模型如下:然后我们可以使用
Address(party=person_instance)
或 <代码>地址(party=organization_instance)。到目前为止,一切都很好。
但是,如果我们尝试获取与代理模型相对应的对象列表,例如使用
Person.objects.all()
,我们会得到一个allParty
对象,即Person
对象和Organization
对象。 这是因为代理模型仍然使用超类(即Party
)中的模型管理器。步骤 2:添加代理模型管理器
为了确保
Person.objects.all()
只返回Person
对象,我们需要分配一个单独的 模型管理器,用于过滤Party
查询集。 为了启用此过滤,我们需要一个字段来指示该对象应使用哪个代理模型。需要明确的是:创建
Person
对象意味着向Party
表添加一行。组织
也是如此。 为了区分两者,我们需要一列来指示一行是代表Person
还是Organization
。 为了方便和清晰起见,我们添加一个名为proxy_name
的字段(即列),并使用它来存储代理类的名称。因此,输入
ProxyManager
模型管理器和proxy_name
字段:现在
Person.objects.all()
返回的查询集将仅包含Person
对象(对于Organization
也是如此)。但是,这在
ForeignKey
与Party
关系的情况下不起作用,如上面的Address.party
所示,因为它总是返回一个Party
实例,无论proxy_name
字段的值如何(另请参阅 文档)。 例如,假设我们创建一个address = Address(party=person_instance)
,那么address.party
将返回一个Party
实例,而不是Person
实例。步骤 3:扩展
Party
构造函数处理相关字段问题的一种方法是扩展
Party.__new__
方法,因此它返回在中指定的类的实例“proxy_name”字段。 最终结果如下所示:现在,如果
proxy_name
字段为Person
,则address.party
实际上将返回一个Person
实例>。最后一步,我们可以使整个事情可重用:
步骤 4:使其可重用
为了使我们的基本单表继承实现可重用,我们可以使用 Django 的抽象继承:
inheritance/models。 py
:然后我们可以实现我们的继承结构,如下所示:
parties/models.py
:根据您的需要,可能需要更多工作,但我相信这涵盖了一些基础知识。
Summary
Django's proxy models provide the basis for Single Table Inheritance.
However, some effort is required to make it work.
Skip to the end for a re-usable example.
Background
Martin Fowler describes Single Table Inheritance (STI) as follows:
This is precisely what Django's proxy model inheritance does.
Note, that, according to this blog post from 2010,
proxy
models have been around since Django 1.1.A "normal" Django model is a concrete model, i.e. it has a dedicated table in the database.
There are two types of Django model that do not have dedicated database tables, viz. abstract models and proxy models:
Abstract models act as superclasses for concrete models. An abstract model can define fields, but it does not have a database table. The fields are only added to the database tables for its concrete subclasses.
Proxy models act as subclasses for concrete models. A proxy model cannot define new fields. Instead, it operates on the database table associated with its concrete superclass. In other words, a Django concrete model and its proxies all share a single table.
Django's proxy models provide the basis for Single Table Inheritance, viz. they allow different models to share a single table, and they allow us to define proxy-specific behavior on the Python side. However, Django's default object-relational mapping (ORM) does not provide all the behavior that would be expected, so a little customization is required. How much, that depends on your needs.
Let's build a minimal example, step by step, based on the simple data-model in the figure below:
Step 1: basic "proxy model inheritance"
Here's the content of
models.py
for a basic proxy inheritance implementation:Person
andOrganization
are two types of parties.Only the
Party
model has a database table, so all the fields are defined on this model, including any fields that are specific either toPerson
or toOrganization
.Because
Party
,Person
, andOrganization
all use theParty
database table, we can define a singleForeignKey
field toParty
, and assign instances of any of the three models to that field, as implied by the inheritance relation in the figure. Note, that, without inheritance, we would need a separateForeignKey
field for each model.For example, suppose we define an
Address
model as follows:We can then initialize an
Address
object using e.g.Address(party=person_instance)
orAddress(party=organization_instance)
.So far, so good.
However, if we try to get a list of objects corresponding to a proxy model, using e.g.
Person.objects.all()
, we get a list of allParty
objects instead, i.e. bothPerson
objects andOrganization
objects. This is because the proxy models still use the model manager from the superclass (i.e.Party
).Step 2: add proxy model managers
To make sure that
Person.objects.all()
only returnsPerson
objects, we need to assign a separate model manager that filters theParty
queryset. To enable this filtering, we need a field that indicates which proxy model should be used for the object.To be clear: creating a
Person
object implies adding a row to theParty
table. The same goes forOrganization
. To distinguish between the two, we need a column to indicate if a row represents aPerson
or anOrganization
. For convenience and clarity, we add a field (i.e. column) calledproxy_name
, and use that to store the name of the proxy class.So, enter the
ProxyManager
model manager and theproxy_name
field:Now the queryset returned by
Person.objects.all()
will only containPerson
objects (and the same forOrganization
).However, this does not work in the case of a
ForeignKey
relation toParty
, as inAddress.party
above, because that will always return aParty
instance, regardless of the value of theproxy_name
field (also see docs). For example, suppose we create anaddress = Address(party=person_instance)
, thenaddress.party
will return aParty
instance, instead of aPerson
instance.Step 3: extend the
Party
constructorOne way to deal with the related-field issue is to extend the
Party.__new__
method, so it returns an instance of the class specified in the 'proxy_name' field. The end result looks like this:Now
address.party
will actually return aPerson
instance if theproxy_name
field isPerson
.As a last step, we can make the whole thing re-usable:
Step 4: make it re-usable
To make our rudimentary Single-Table Inheritance implementation re-usable, we can use Django's abstract inheritance:
inheritance/models.py
:Then we can implement our inheritance structure as follows:
parties/models.py
:More work may be required, depending on your needs, but I believe this covers some of the basics.
我认为OP正在询问此处定义的单表继承:
也就是说,实体类的整个层次结构的单个数据库表。 Django 不支持这种继承。
I think the OP is asking about Single-Table Inheritance as defined here:
That is, a single database table for a whole hierarchy of entity classes. Django does not support that kind of inheritance.
目前Django中有两种继承形式——MTI(模型表继承)和ABC(抽象基类)。
我写了一个 教程,了解幕后发生的事情。
您还可以参考关于模型继承的官方文档。
There are currently two forms of inheritance in Django - MTI (model table inheritance) and ABC (abstract base classes).
I wrote a tutorial on what's going on under the hood.
You can also reference the official docs on model inheritance.
查看我的尝试:
http://djangosnippets.org/snippets/2408/
不完全是“单表继承”,但对于许多情况来说已经足够接近了。
See my attempt:
http://djangosnippets.org/snippets/2408/
Not exactly "single table inheritance", but close enough for many situations.
这可能有用: https://github.com/craigds/django-typed-models< /a>
它看起来有点像单表继承的实现,但它有一个限制,即子类不能有任何额外的字段。
以下是 django 开发者邮件列表上最近关于 STI 的讨论:
https://groups.google.com/forum/# !msg/django-developers/-UOM8HNUnxg/6k34kopzerEJ
this might be of use: https://github.com/craigds/django-typed-models
It looks to be somewhat of an implementation of Single Table Inheritance but it has the limitation that subclasses can't have any extra fields.
here is a recent discussion on the django developer mailing list about STI:
https://groups.google.com/forum/#!msg/django-developers/-UOM8HNUnxg/6k34kopzerEJ
我认为你可以做类似的事情。
我必须自己实现这个问题的解决方案,这就是我解决它的方法:
这可能有一些锁定问题...我不太确定 django 如何处理这个问题。 另外,我并没有真正测试上面的代码,它纯粹是为了娱乐目的,希望能让你走上正轨。
I think you can do something akin to this.
I have to implement a solution for this problem myself, and here was how I solved it:
This may have some locking issues... I'm not really sure how django handles that off the top of my head. Also, I didn't really test the above code, it's strictly for entertainment purposes, to hopefully put you on the right track.