Django使用Mixin保存多对多关系时提示id字段未赋值错误如何解决
报错原因
needs to have a value for field "id" before this many-to-many relationship can be used
该报错的核心逻辑是:Django的多对多关系依赖中间表存储两个关联模型的主键映射,你调用form.save(commit=False)的时候,只是生成了Reportmodel的内存实例,还没有写入数据库生成主键id,此时无法操作多对多字段category。
管理员场景下你直接调用form.save(),会先把Reportmodel实例写入数据库生成主键,再处理表单提交的多对多数据,所以不会报错。
另外还有一个隐藏问题:ManyToManyField.set()方法要求传入的是可迭代对象(比如列表、查询集),你直接传入单个Categorymodel实例也会触发参数错误。
修复方案
修改FormValidMixin的form_valid方法逻辑:
- 给
commit=False生成的实例设置完user后,先调用一次save()把实例写入数据库,生成主键id - 调用
category.set()的时候把单个实例包裹成列表传入
修复后的代码:
class FormValidMixin(): def form_valid(self,form): if self.request.user.is_admin: form.save() else: category1 = Categorymodel.objects.get(position=1) self.obj = form.save(commit=False) self.obj.user = self.request.user # 先保存主表实例,生成主键id self.obj.save() # set方法传入可迭代对象,这里把单个实例放到列表里 self.obj.category.set([category1]) # 补充form_valid标准返回逻辑,原代码缺失会触发视图报错 return super().form_valid(form)
可选优化
如果要把设置默认category的逻辑内聚到模型层,避免每次视图层都要手动处理,可以重写Reportmodel的save方法:
class Reportmodel(models.Model): subject=models.CharField(max_length=100) category=models.ManyToManyField(Categorymodel,related_name='info') user=models.ForeignKey(User,on_delete=models.CASCADE) def save(self, *args, **kwargs): # 判断是不是首次创建的实例 is_new = self.pk is None super().save(*args, **kwargs) # 新创建且未设置category时自动填充默认值 if is_new and not self.category.exists(): default_category = Categorymodel.objects.get(position=1) self.category.add(default_category)
调整后视图层不需要额外处理category的默认值逻辑,普通用户提交时只要设置完user调用save即可。
内容的提问来源于stack exchange,提问作者Hossein MEY
相关产品推荐
相关产品推荐

