ForeignKey 而不是 ManyToManyField 的优缺点是啥
Posted
技术标签:
【中文标题】ForeignKey 而不是 ManyToManyField 的优缺点是啥【英文标题】:What's the pros and cons of ForeignKey instead of ManyToManyFieldForeignKey 而不是 ManyToManyField 的优缺点是什么 【发布时间】:2016-10-08 10:08:00 【问题描述】:在 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)
但我总是想知道为什么他们不实现多对多关系:
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)
有什么好处和坏处?
【问题讨论】:
它们是完全不同的东西,外键是一对多的关系。 是的,我知道。但他们为什么选择 ForeignKey?一个问题有很多选择,同一个选择可以用在很多问题中 【参考方案1】:我确信他们在教程中使用了 ForeignKey(一对多)关系,因为他们试图使示例尽可能简单,只有两个模型:Question
和 Choice
。请注意,votes
是 Choice
模型的一个字段,这使得显示投票结果变得非常简单。
如果您在进行民意调查时对每个问题都有相同的选择(非常同意、有点同意等),那么多对多关系可能是合适的。但这使事情变得更加复杂。您提出的多对多关系模型是:
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
表的一个字段,但现在每个选项都适用于许多问题。您可以看到“强烈同意”选项获得了 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)
现在您可以将每个问题-选择组合的投票人数精确地制成表格,但它更复杂,不太适合入门教程。
使用您提出的 ManyToMany 模型,Django 将在幕后自动创建 QuestionChoices
模型,但要将 votes
字段附加到它,您必须自己明确地进行。
如果您的关系可以建模为 OneToMany 或 ManyToMany,则优缺点取决于您的特定应用程序。通常,您希望使用最准确地反映现实生活情况的模型。但是您还必须考虑如何更新和汇总数据,并尝试达成最佳折衷方案。根据我的经验,选择困难的情况并不多。
【讨论】:
非常感谢。这是关于理论和实际问题的非常详细的描述以上是关于ForeignKey 而不是 ManyToManyField 的优缺点是啥的主要内容,如果未能解决你的问题,请参考以下文章
Django:如何从 ManyToMany 迁移到 ForeignKey?
django DetailView 没有从 ManyToMany 字段中捕获数据
Django ForeignKey.limit_choices_to 与 ForeignKey to ManyToMany 场景
ManytoMany 字段中的 Django ForeignKey 显示为 None