Django中ManyToManyField关系能否修改中间模型并保留原有关联?
完全可以在添加多对多关系额外字段的同时,完整保留所有历史关联数据,操作步骤如下:
- 第一步:确认原有自动生成的中间表名称
Django默认生成的多对多中间表命名规则为{所属应用名}_{小写主模型名}_{小写多对多字段名},比如Article模型位于名为content的应用下,多对多字段名为publications,则原有中间表名为content_article_publications,也可以直接查询数据库获取准确表名。 - 第二步:调整中间模型的配置
在你定义的Enrollment模型的Meta类中,新增db_table参数,值为上一步查到的原有中间表名,示例代码如下:class Enrollment(models.Model): article = models.ForeignKey(Article, on_delete=models.CASCADE) publication = models.ForeignKey(Publication, on_delete=models.CASCADE) date_joined = models.DateField(null=True, default=None, blank=True) class Meta: unique_together = [['article', 'publication']] db_table = 'content_article_publications' # 替换为你实际的原有中间表名 - 第三步:生成并执行迁移
直接执行以下两条命令即可:
此时Django不会新建中间表,只会在原有中间表的基础上新增python manage.py makemigrations python manage.py migratedate_joined字段,已有的article和publication关联数据不会发生任何变动。
注意事项
- 由于
date_joined字段设置了允许为空,原有操作如article.publications.add(publication实例)仍然可以正常使用;如果后续将date_joined改为必填字段,则必须通过创建Enrollment实例的方式来新建关联关系,不能再直接使用add方法。 - 可以直接通过
Enrollment模型查询带额外字段的关联数据,例如查询某篇文章的所有关联出版方及关联时间:article = Article.objects.get(id=1) enrollments = Enrollment.objects.filter(article=article).select_related('publication') for en in enrollments: print(en.publication.title, en.date_joined)
内容的提问来源于stack exchange,提问作者Diego Silvera
相关产品推荐
相关产品推荐

