使用GenericForeignKey与多重继承与OneToOneField相比,有什么优缺点?

spe*_*ras 8 database django

上下文

我正在使用Django模型建模我的数据.主要模型是Article.它包含实际内容.

然后每个Article必须附加到一组文章.那些群体可能是a Blog,Categorya Portfolio或a Story.每一个都Article必须附在一个,而且恰好是其中之一.也就是说,无论是博客,类别还是故事.这些模型具有非常不同的领域和功能.

我想到了达到目标的三种方法(以及真正看起来错误的奖励).

选项#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
Run Code Online (Sandbox Code Playgroud)

在数据库方面,这意味着模型之间实际上不存在任何关系,它们由Django强制执行.

选项#2:多重继承

使文章组全部从ArticleGroup模型继承.这看起来像这样:

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
Run Code Online (Sandbox Code Playgroud)

在数据库方面,这创造了一个额外的表ArticleGroup,然后CategoryBlog有一个隐含的外键,该表作为其主键.

旁注:我知道有一个包可以自动记录这些结构.

选项#3:手动OneToOneFields

在数据库方面,它相当于选项#2.但是在代码中,所有关系都是明确的:

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
Run Code Online (Sandbox Code Playgroud)

除了明确说明Django的继承魔法隐含地做什么之外,我真的不明白这是什么意思.

奖金:多列

这似乎很肮脏的,所以我就把它添加作为奖金,但它也有可能定义一个可空ForeignKey的每一个的Category,Blog直接在... Article模型.

所以...

......我无法在这些之间做出真正的决定.每种方法的优缺点是什么?有一些最佳做法吗?我错过了更好的方法吗?

如果这很重要,我正在使用Django 1.8.

spe*_*ras 5

似乎没有人建议分享这一点。尽管说它看起来很丑,但我最终还是选择了多列选项。归结为三件事:

  • 基于数据库的可执行性。
  • Django ORM与不同构造一起工作的方式。
  • 我自己的需求(即,对组进行集合查询以获取项目列表,对项目进行单个查询以获取组)。

选项1

  • 无法在数据库级别强制执行。
  • 在查询上可能很有效,因为其构造方式不会落入通常的通用外键陷阱中。这些发生在项目是通用的而不是集合时。
  • 但是,由于ORM如何处理GFK,因此无法使用我需要的自定义管理器,因为我的文章是使用django-hvad翻译的。

选项#2

  • 可以在数据库级别执行。
  • 可能有些高效,但会遇到ORM限制,这显然不是围绕这种用法构建的。除非我extra()大量使用或自定义查询,但是在某些时候,没有理由再使用ORM了。

选项#3

  • 实际上会比#2好一点,因为使事物明确化可以使使用ORM时更容易进行查询优化。

多列

  • 事实证明还不错。可以在数据库级别强制执行(FK约束加上手动CHECK以确保只有一列为非空)。
  • 简单高效。一个直观的查询即可完成工作:select_related('category', 'blog', ...)
  • 尽管确实存在难以扩展的问题(任何新类型也将需要更改Article的表)并限制了可能的类型数量,但我不太可能遇到这些问题。

希望它对遇到同样困境但仍然有兴趣听取其他意见的人有所帮助。

  • 我同意 - 多列选项是最好的,只要您预计可能只有有限数量的可能与之相关的类。对于这个用例,GFK 是邪恶的 IMO,因为它在您的数据库完整性中出现了一个漏洞,并使 Django 之外的查询变得特别困难。 (2认同)