问题描述
上下文
我正在使用Django模型对数据进行建模。
主要模型是 Article
。它保留了实际内容。
I am in the process of modeling my data using Django models.The main model is an Article
. It holds the actual content.
然后,每个 Article
必须附加到一组文章中。这些组可能是博客
,类别
和投资组合
或故事
。每个 Article
必须附加一个,也必须附加其中一个。即,博客,类别或故事。这些模型具有不同的领域和功能。
Then each Article
must be attached to a group of articles. Those group may be a Blog
, a Category
a Portfolio
or a Story
. Every Article
must be attached to one, and exactly one of those. That is, either a blog, a category or a story. Those models have very different fields and features.
我想到了实现该目标的三种方法(还有一个看起来确实不对的奖励)。
I thought of three ways to reach that goal (and a bonus one that really looks wrong).
选项1:通用外键
与 django.contrib相同.contenttypes.fields.GenericForeignKey
。看起来像这样:
class Category(Model):
# some fields
class Blog(Model):
# some fields
class Article(Model):
group_type = ForeignKey(ContentType)
group_id = PositiveIntegerField()
group = GenericForeignKey('group_type', 'group_id')
# some fields
数据库端,这意味着模型之间实际上不存在任何关系,它们是由Django强制执行的。
On the database side, that means no relation actually exists between the models, they are enforced by Django.
选项#2:多表继承
使所有文章组都从 ArticleGroup
模型继承。看起来像这样:
Make article groups all inherit from an ArticleGroup
model. This would look like this:
class ArticleGroup(Model):
group_type = ForeignKey(ContentType)
class Category(ArticleGroup):
# some fields
class Blog(ArticleGroup):
# some fields
class Article(Model):
group = ForeignKey(ArticleGroup)
# some fields
数据库端,这会为 ArticleGroup
创建一个附加表,然后为 Category
和 Blog
具有该表的隐式外键作为其主键。
On the database side, this creates an additional table for ArticleGroup
, then Category
and Blog
have an implicit foreign key to that table as their primary key.
侧面注:我知道有,用于自动记录此类构造。
Sidenote: I know there is a package that automates the bookkeeping of such constructions.
选项#3:手动OneToOneFields
在数据库端,它等效于选项#2。但是在代码中,所有关系都明确了:
On the database side, it is equivalent to option #2. But in the code, all relations are made explicit:
class ArticleGroup(Model):
group_type = ForeignKey(ContentType)
class Category(Model):
id = OneToOneField(ArticleGroup, primary_key=True)
# some fields
class Blog(Model):
id = OneToOneField(ArticleGroup, primary_key=True)
# some fields
class Article(Model):
group = ForeignKey(ArticleGroup)
# some fields
除了明确指出什么之外,我真的不知道这是什么意思
I don't really see what the point of that would be, apart from making explicit what Django's inheritance magic implicitly does.
奖金:多列
这似乎很脏。因此我只是将其添加为奖励,但也有可能为类别
,博客$ c $中的每个类别定义可为空的ForeignKey c>,...直接在
Article
模型上。
It seems pretty dirty so I just add it as a bonus, but it would also be possible to define a nullable ForeignKey to each of Category
, Blog
, ... directly on the Article
model.
所以...
...我无法获得在这些之间做出决定。每种方法的优缺点是什么?有一些最佳做法吗?我错过了更好的方法吗?
...I cannot really decide between those. What are the pros and cons of each approach? Are there some best practices? Did I miss a better approach?
如果那很重要,我正在使用Django 1.8。
If that matters, I'm using Django 1.8.
推荐答案
似乎没有人建议分享。
尽管我说它看起来很丑,但我最终还是选择了多列选项。归结为三件事:
It seems noone had advice to share on that one.I eventually chose the multicolumn option, despite having said it looked ugly. It all came down to 3 things:
- 基于数据库的可执行性。
- Django ORM的方式
- 我自己的需求(即,对组进行集合查询以获取项目列表,对项进行单个查询以获取组)。
选项#1
- 无法在数据库级别强制执行。
- 在查询上可能很有效,因为其构造方式不会陷入通常的通用外键陷阱。发生这种情况的原因是项目是通用的,而不是集合的。
- 但是,由于ORM如何处理GFK,因此无法使用自定义管理器,因为我的文章已翻译,所以我不需要使用。
- Cannot be enforced at the database level.
- Could be efficient on queries because the way it is constructed does not fall into usual generic foreign key pitfalls. Those happen when the items are generic, not the collections.
- However, due to how the ORM handles GFK, it is impossible to use a custom manager, which I need because my articles are translated using django-hvad.
选项#2
- 可以在数据库级别强制执行。
- 可能有些效率,但是遇到了ORM限制,这显然不是围绕这种用法构建的。除非我大量使用
extra()
或自定义查询,但是在某些时候,没有理由再使用ORM了。
- Can be enforced at the database level.
- Could be somewhat efficient, but runs into ORM limitations, which is clearly not built around this use. Unless I use
extra()
or custom queries alot, but at some point there is no reason to use an ORM anymore.
选项#3
- 实际上会比#2,因为使事情明确,可以在使用ORM时简化查询优化。
多列
- 结果还不错。可以在数据库级别强制执行此操作(FK约束加上手动的CHECK以确保只有一列为非空)。
- 简单高效。一个直观的查询即可完成此工作:
select_related('category','blog',...)
。 - 尽管存在难以扩展的问题(任何新类型都将需要更改
Article
的表)并限制了可能的类型数量,因此我不太可能运行
- Turns out not being so bad. It can be enforced at the database level (FK constraints plus a manual CHECK to ensure only one of the columns is non-null).
- Easy and efficient. A single intuitive query does the job:
select_related('category', 'blog', ...)
. - Though it does have the issue of being harder to extend (any new type will require altering the
Article
's table as well) and limiting the possible number of types, I'm unlikely to run into those.
希望它可以帮助遇到同样困境但仍然有兴趣听取其他意见的任何人。
Hope it helps anyone with the same dilemma, and still interested in hearing other opinions.
这篇关于使用GenericForeignKey与多表继承与OneToOneField的优缺点是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!