这很棘手。我认为您可以通过多种方式对此进行建模。
使用您当前的方式,您可以在应用程序中强制执行唯一性约束。
class Comment(models.Model):
article = models.ForeignKey(Article)
comic = models.ForeignKey(Comic)
def save(self, *args, **kwargs):
# assert that there is either comic OR article but not both
super(Comment, self).save(*args, **kwargs)
通过这种方式,如果您添加另一个您希望Comment 引用的模型会发生什么?您必须在保存方法中手动添加新类型的条件并执行迁移。
Django 提供了 GenericForeignKey 字段,允许您从 Comment 引用任何模型。 https://docs.djangoproject.com/en/1.8/ref/contrib/contenttypes/#generic-relations
这将允许您创建从Comment 到文章或漫画的通用引用,并且由于它只有一个字段,默认情况下是互斥的。我发现查询和使用GenericeForeignKeys 很尴尬;但它们仍然是一种选择,可能适合您的用例。
另一个强大的选项(我最喜欢的)可能是创建一个多态模型,这也是互斥的。
每个Comment 可以使用模型继承引用Content 的通用片段。 (我没有测试以下内容,所以它可能无法复制/粘贴)
class Content(models.Model):
objects = InheritanceManager()
# shared content fields could be stored in this model
class Article(Content):
# article specific fields
class Comic(Content):
# comic specific fields
class Comment(models.Model):
content = models.OneToOneField(Content)
这是对Comment 与任何Content 的关系进行建模的强大方法。这确实会增加额外的查询开销,并且应该保证对您的用例进行审计。
InheritanceManager 是 django-model-utils 包提供的实用程序,非常轻量级。我已经在生产环境中使用它并且它是高性能的,只要您了解使用它对数据建模所涉及的额外查询。 https://django-model-utils.readthedocs.org/en/latest/managers.html#inheritancemanager
文档中解释了查询开销。
如果您认为将来会添加额外的 Content 子类,这可能是一种可扩展的方式来模拟您的关系,并在过滤方面提供比 GenericForeignKeys 更大的灵活性。