使用GenericForeignKey和多重继承与OneToOneField的优缺点是什么?

时间:2015-05-31 19:56:29

标签: django database

上下文

我正在使用Django模型对数据进行建模。 主要模型是Article。它包含实际内容。

然后每个Article必须附加到一组文章。这些群组可能是BlogCategoryPortfolioStory。每个Article必须附加到一个{,1}。也就是说,无论是博客,类别还是故事。这些模型具有非常不同的领域和特征。

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

选项#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强制执行。

选项#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

在数据库方面,这会为ArticleGroup创建一个附加表,然后CategoryBlog将该表的隐式外键作为其主键。

旁注:我知道有a package可以自动记录这些结构。

选项#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

除了明确Django的继承魔法隐含的内容之外,我真的不明白这是什么意思。

加分:多列

它看起来很脏,所以我只是添加它作为奖励,但也可以直接在{{CategoryBlog,...定义一个可为空的ForeignKey。 1}}模型。

因此...

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

如果重要,我会使用Django 1.8。

1 个答案:

答案 0 :(得分:5)

似乎没有人建议分享那个。 我最终选择了多列选项,尽管说它看起来很难看。这一切都归结为三件事:

  • 基于数据库的可执行性。
  • Django ORM使用不同结构的方式。
  • 我自己的需求(即,对群组进行集合查询以获取项目列表,以及对项目进行单独查询以获取群组)。

选项#1

  • 无法在数据库级别强制执行。
  • 可以提高查询的效率,因为它的构建方式不会落入通常的通用外键缺陷中。当项目是通用的而不是集合时会发生这种情况。
  • 但是,由于ORM处理GFK的方式,我不可能使用自定义管理器,因为我的文章是使用django-hvad翻译的。

选项#2

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

选项#3

  • 实际上会比#2好一些,因为使用ORM可以更容易地进行查询优化。

<强>多列

  • 原来并不是那么糟糕。它可以在数据库级别强制执行(FK约束加上手动CHECK以确保只有一列非空)。
  • 简单高效。一个直观的查询可以完成工作:select_related('category', 'blog', ...)
  • 虽然它确实存在难以扩展的问题(任何新类型都需要更改Article的表)并限制可能的类型数量,但我不太可能遇到这些问题。

希望它可以帮助任何有同样困境的人,并且仍然有兴趣听取其他意见。