ForeignKey 而不是 ManyToManyField 的优缺点是什么

What's the pros and cons of ForeignKey instead of ManyToManyField

在 django 中 tutorial 它模拟了一个轮询结构:

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

但我一直想知道为什么他们不实现 ManyToMany 关系:

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    choices = models.ManyToManyField(Choice)

class Choice(models.Model):
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

优缺点是什么?

我确定他们在教程中使用了外键(一对多)关系,因为他们试图让示例尽可能简单,只有两个模型:QuestionChoice.请注意,votesChoice 模型的一个字段,这使得显示投票结果变得非常简单。

如果您在进行民意调查时对每个问题都有相同的选择(强烈同意、有点同意等),那么多对多关系可能是合适的。但这让事情变得更加复杂。您建议的多对多关系模型是:

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    choices = models.ManyToManyField(Choice)

class Choice(models.Model):
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

但如果不进行一些更改,这将无法正常工作。votes 仍然是 Choice table 的一个字段,但现在每个选择都适用于许多问题。您将能够看到“强烈同意”选项获得了 38 票,但您无法判断选民同意哪些问题。为了能够正确地列出选票,你必须做类似

的事情
from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    choices = models.ManyToManyField('Choice', through='QuestionChoices')

class Choice(models.Model):
    choice_text = models.CharField(max_length=200)

class QuestionChoices(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice = models.ForeignKey(Choice, on_delete=models.CASCADE)
    votes = models.IntegerField(default=0)

现在您可以准确地列出有多少人为每个问题-选择组合投票,但它更复杂并且不太适合table入门教程。

对于您提出的 ManyToMany 模型,Django 会在幕后自动创建 QuestionChoices 模型,但为了将 votes 字段附加到它,您必须自己明确地执行此操作。

如果您的关系可以建模为 OneToMany 或 ManyToMany,则优缺点取决于您的特定应用程序。通常,您希望使用最准确地反映现实生活情况的模型。但你也得考虑你需要如何更新和汇总数据,并尝试达成最佳折衷。根据我的经验,选择困难的情况并不多。