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(一对多)关系,因为他们试图使示例尽可能简单,只有两个模型: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 表的一个字段,但现在每个选项都适用于许多问题。您可以看到“强烈同意”选项获得了 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

在 ManyToMany ForeignKey 字段的模板中获取值

Django笔记七之ManyToMany和OneToOne介绍