升级至Django 1.11时出现多对多关系列不存在问题求助
解决Django 1.11升级后自定义多对多Through表失效的问题
嘿,我太懂这种升级后突然掉坑的感觉了!Django 1.11在多对多关系的through表处理上,确实强化了不少一致性校验,尤其是你这种“借用”自动生成的中间表来扩展字段的操作,很容易触发之前没遇到的问题。下面给你一步步拆解解决方案:
1. 精准匹配原有中间表结构,重建自定义Through模型
你之前“借用”的api_session_pollgroups是Django自动生成的多对多中间表,它默认包含两个外键字段(对应Session和PollGroup模型),还有唯一联合约束。Django 1.11会严格校验自定义through模型和实际表结构的一致性,所以必须精准复刻这些内容,再加上你的order字段:
from django.db import models from .models import Session, PollGroup class SessionPollGroup(models.Model): # 必须和原有表的外键字段名完全一致,用db_column确保映射正确 session = models.ForeignKey(Session, on_delete=models.CASCADE, db_column='session_id') pollgroup = models.ForeignKey(PollGroup, on_delete=models.CASCADE, db_column='pollgroup_id') # 你的自定义排序字段 order = models.IntegerField(default=0) class Meta: # 明确指定使用已存在的表,不能写错表名 db_table = 'api_session_pollgroups' # 原有自动生成表自带的唯一约束,必须加上,否则Django 1.11会报错 unique_together = ('session', 'pollgroup') # 可选:如果需要默认按order排序,可以加上这行 ordering = ['order']
2. 修正Session模型的多对多关系定义
确保你的Session模型里的多对多字段,正确指向这个自定义的through模型,参数要和之前保持一致(比如related_name):
class Session(models.Model): # 其他模型字段... poll_groups = models.ManyToManyField( PollGroup, through='SessionPollGroup', related_name='sessions' # 如果之前有这个参数,一定要保留 )
3. 处理迁移:避免重复创建表,只添加order字段
因为你是在已有表上扩展字段,不能让Django自动生成创建表的迁移。你需要手动生成空迁移,然后添加字段操作:
- 首先生成一个空迁移文件:
python manage.py makemigrations --empty your_app_name - 打开生成的迁移文件,修改成只添加
order字段的操作:from django.db import migrations, models class Migration(migrations.Migration): # 替换成你上一个迁移的名称 dependencies = [ ('your_app_name', '00XX_previous_migration'), ] operations = [ migrations.AddField( model_name='sessionpollgroup', name='order', field=models.IntegerField(default=0), ), ] - 最后执行迁移:
python manage.py migrate
4. 调整单元测试中的多对多操作逻辑
Django 1.11对自定义through表的add()/remove()方法限制更严格——默认的add()不会处理自定义字段(比如你的order),所以如果测试里有直接调用session.poll_groups.add(pollgroup)的代码,需要改成显式创建中间表实例:
原来的代码:
session.poll_groups.add(pollgroup)
改成:
SessionPollGroup.objects.create(session=session, pollgroup=pollgroup, order=1)
如果需要批量添加,记得给每个实例指定对应的order值。
额外注意点
- 可以用
python manage.py inspectdb api_session_pollgroups命令,生成原有表的模型代码,对比你的自定义模型,确保字段、约束完全一致,别漏了任何细节。 - 如果你之前给中间表加过索引,也要在自定义模型的Meta里用
indexes声明出来,Django 1.11会校验索引的存在。
内容的提问来源于stack exchange,提问作者bharling
相关产品推荐
相关产品推荐

