Django - 如何构建适合的中间 m2m 模型? / 最佳实践

Posted

技术标签:

【中文标题】Django - 如何构建适合的中间 m2m 模型? / 最佳实践【英文标题】:Django - How to build an intermediate m2m model that fits? / best practice 【发布时间】:2016-08-28 20:24:12 【问题描述】:

首先,我必须承认,我对所有这些编码内容都很陌生,但由于我自己找不到合适的解决方案,因此学习编码可能是最好的方法。

无论如何,我正在尝试构建一个应用程序来展示不同的冠军、冠军和类似的东西。在阅读了 Django 文档后,我发现我必须使用中间模型作为更好的方法。我的旧 models.py 看起来像这样:

class Person(models.Model):
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)
    [...]

class Team(models.Model):
    name = models.CharField(max_length=64)
    team_member_one = models.ForeignKey(Person)
    team_member_two = models.ForeignKey(Person)

class Championship(models.Model):
    name = models.CharField(max_length=128)
    status = models.BooleanField(default=True)

class Titleholder(models.Model):
    championship = models.ForeignKey(Championship)
    date_won = models.DateField(null=True,blank=True)
    date_lost = models.DateField(null=True,blank=True)
    titleholder_one = models.ForeignKey(Person,related_name='titleholder_one',null=True,blank=True)
    titleholder_two = models.ForeignKey(Person,related_name='titleholder_two',null=True,blank=True)

个人或团队都可以赢得冠军,这取决于是单打冠军还是团体冠军,这就是为什么我必须在 Titleholder 类中使用外键。看着Django documentation 这似乎是错误的。另一方面,对于我作为初学者来说,示例中的中间模型似乎与我的模型完全不匹配。

长话短说:谁能指出我如何以正确的方式构建模型的正确方向?注意:这只是一个关于如何构建模型并在 Django 管理中显示它的问题,我什至现在还没有谈论构建模板。

我们将不胜感激!在此先感谢各位。

【问题讨论】:

Django 的ManyToManyField 只是用于自动创建和查询中间表的语法糖。如果您明确创建表,就像您在这里所做的那样,那么您不需要该字段(尽管它仍然很有帮助)。但是,您提供的架构存在许多问题。它们都与 Django 无关,这是 SQL 数据库建模的问题。我建议问一个更一般的问题(我如何为这些数据建模?这是我尝试过的......)并用database-design 或data-modeling 标记它。 【参考方案1】:

所以我会从头开始。您似乎对 E-R 数据库建模有些陌生。如果我试图做你所做的事情,我会按照以下方式创建我的模型。

首先,Team 将成为我的“角落”模型(我用这个术语表示没有任何 FK 字段的模型),然后 Person 模型将发挥作用,如下所示。

class Team(models.Model):
    name = models.CharField(max_length=64)

class Person(models.Model):
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)
    team = models.ForeignKey(to=Team, null=True, blank=True, related_name='members')

这有效地使模型具有可扩展性,即使您的团队中永远不会有超过两个人,这也是一种很好的做法。

接下来是冠军模式。我会将此模型与 Person 模型直接连接为与“通过”模型的多对多关系,如下所示。

class Championship(models.Model):
    name = models.CharField(max_length=64)
    status = models.BooleanField(default=False) # This is not a great name for a field. I think should be more meaningful.
    winners = models.ManyToManyField(to=Person, related_name='championships', through='Title')

class Title(models.Model):
    championship = models.ForeignKey(to=Championship, related_name='titles')
    winner = models.ForeignKey(to=Person, related_name='titles')
    date = models.DateField(null=True, blank=True)

根据我的理解,这正是我会做的方式。我敢肯定我不明白你试图做的一切。随着我的理解发生变化,我可能会修改这些模型以满足我的需要。

可以采用的另一种方法是使用 GenericForeignKey 字段来创建一个字段,该字段可以是 Team 模型或 Person 模型的 FK。或者可以更改的另一件事是您添加另一个模型来保存每次举行冠军赛的详细信息。有很多方法可以解决它,但没有一种正确的方法。

如果您有任何问题或任何我尚未处理的问题,请告诉我。我会根据需要尝试修改答案。

【讨论】:

以上是关于Django - 如何构建适合的中间 m2m 模型? / 最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

更新 Django 中现有的 M2M 关系

django 无法在指定中间模型的 ManyToManyField 上设置值。改用管理器

Django 模板 - 按名称访问 M2M 属性和值

django m2m 模型不同步

如何避免 django“与相关 m2m 字段冲突”错误?

Django多对多(m2m)与同一模型的关系