Django:使用ContentType与multi_table_inheritance

时间:2012-10-08 13:32:46

标签: django django-models

我遇到了类似的问题 How to query abstract-class-based objects in Django? 该线程建议使用multi_table_inheritance。我个人认为使用content_type在概念上更舒适(只是感觉更接近逻辑,至少对我而言)

使用上一个链接中的示例,我只需将StelarType添加为

class StellarType(models.Model):
    """
    Use ContentType so we have a single access to all types
    """
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

然后将其添加到抽象基础模型

class StellarObject(BaseModel):
    title = models.CharField(max_length=255)
    description = models.TextField()
    slug = models.SlugField(blank=True, null=True)
    stellartype = generic.GenericForeignKey(StellarType)
    class Meta:
        abstract = True

要在StellarObject和StellarType之间进行同步,我们可以连接post_save信号,以便在每次创建Planet或Star时创建StellarType实例。通过这种方式,我可以通过StellarType查询StellarObjects。 所以我想知道使用这种方法反对使用multi_table_inheritance的PRO和CON是什么?我认为两者都在数据库中创建了一个额外的表。但是数据库性能呢?可用性/灵活性如何?感谢您的任何意见!

2 个答案:

答案 0 :(得分:5)

对我来说,当你想要将一个对象与很多基本不属于同一“类型”的模型之一联系起来时,ContentType就是你的选择。就像您希望能够在社交网络上对用户,页面和图片进行关键评论一样,但这三个模型没有共享的合理超类型。当然你可以创建一个“可评论的”超类型,但对我来说,感觉更像是一个混合而不是这三个东西衍生出来的基本类型。在ContentType问世之前,你别无选择,只能为这些关系创建超类型,如果你需要在同一个应用程序中多次执行它,这会很快变得非常难看(假设你还有事件,提醒,消息等,每个消息可以应用于不同的模型集)。

当您想要将属性附加到基本模型时,多表继承最有意义,这样它们将在从其扩展的所有具体模型中共享,以便您可以获得多态行为。 Commentable并不适合这种模式,因为所有这些行为都可以放在Comment模型上,而不是评论对象。但是,如果您有不同类别的用户,他们共享大部分相同的行为并且应该是可聚合的,那么它会更有意义。

对我来说,多表继承的主要优点是更清晰的数据模型,可以在Python端利用隐式关系和继承(虽然多态性仍然有点混乱,如here所示和here)。 ContentType的主要优点是它更通用,并且保留了模型之外的辅助功能,代价是稍微不那么原始的模式(模型上的许多“元”字段用于定义这些关系)。而对于你的例子,你仍然必须依赖post_save,这似乎对我来说似乎不必要的混乱/魔法。

答案 1 :(得分:0)

抱歉恢复旧线程。我认为这一切归结为查找方向。无论是查找某个FK(多重继承)的所有子类,还是将引用的类定义为内容类型,并根据表引用和id(contenttypes)查找它,性能没有太大差别 - 提示:它们都很糟糕。如果您希望您的应用程序易于扩展,我认为内容类型是一个不错的选择,即其他人可以添加新的内容类型以供参考。如果您有时只需要额外表中定义的额外列,则Multitable很好。有时候合并所有子类型并且只有一个在大多数情况下只剩下几个字段的字段也是个好主意。