【问题标题】:How to create a many to one relationship in Django?如何在 Django 中创建多对一关系?
【发布时间】:2015-06-27 15:42:13
【问题描述】:

正如问题所述,如何在 django 模型中创建多对一关系?

基本上,我有两个模型:文章和漫画,我想要一个评论模型,它与文章和漫画都有关系,但不是两者都有关系。 因此,如果 Comment 对象与 Article 对象有关系,那么它不会与 Comic 对象有关系。

我目前正在按照以下方式进行操作,但不起作用:

class Article(models.Model):
    #other fields
class Comic(models.Model):
    #other fields
class Comment(models.Model):
    article = models.ForeignKey(Article)
    comic = models.ForeignKey(Comic)

非常感谢您的帮助。

【问题讨论】:

  • 您遇到错误了吗?你能发布完整的回溯吗?

标签: python django database relationship many-to-one


【解决方案1】:

这很棘手。我认为您可以通过多种方式对此进行建模。

使用您当前的方式,您可以在应用程序中强制执行唯一性约束。

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 更大的灵活性。

【讨论】:

  • 嗯,我知道这是一个复杂的问题。感谢您的解决方案,我会尝试一下。
【解决方案2】:

好吧,您可以向您的 Comment 模型添加另一个字段。喜欢

class Comment(models.Model):
    article = models.ForeignKey(Article, null = True)
    comic = models.ForeignKey(Comic, null = True)
    assigned = models.BooleanField(initial=False)

创建评论对象后,将文章或漫画指向另一个对象并设置为真。

【讨论】:

    猜你喜欢
    • 2011-07-09
    • 1970-01-01
    • 2017-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多