Django中使用commit=False后如何保存多对多字段数据
Django多对多字段保存问题解决
问题背景
在Django项目中,使用ModelForm创建Vendor实例时,通过save(commit=False)暂存实例并设置created_by为当前登录用户,同时需要关联Session中传递的Branch(多对多字段),但现有代码无法正确保存多对多关系,需修正实现方式。
现有代码
models.py
class Branch(models.Model): # Branch Master status_type = ( ("a",'Active'), ("d",'Deactive'), ) name = models.CharField(max_length=100, unique=True) suffix = models.CharField(max_length=8, unique=True) Remark = models.CharField(max_length=200, null=True, blank=True) created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) create_at = models.DateTimeField(auto_now_add=True) update_at = models.DateTimeField(auto_now=True) status = models.CharField(max_length=1, choices = status_type, default = 'a') def __str__(self): return self.name class Vendor(models.Model): status_type = ( ("a",'Active'), ("d",'Deactive'), ) branch = models.ManyToManyField(Branch) company = models.CharField(max_length=200) name = models.CharField(max_length=200) phone = models.CharField(max_length=11, unique = True) email = models.EmailField(max_length=254, unique = True) gst = models.CharField(max_length=15, unique = True) pan_no = models.CharField(max_length=10, unique = True) add_1 = models.CharField(max_length=50, null=True, blank = True) add_2 = models.CharField(max_length=50, null=True, blank = True) add_3 = models.CharField(max_length=50, null=True, blank = True) Remark = models.CharField(max_length=200, null=True, blank=True) created_by = models.ForeignKey(User, on_delete=models.CASCADE) create_at = models.DateTimeField(auto_now_add=True) update_at = models.DateTimeField(auto_now=True) status = models.CharField(max_length=1, choices = status_type, default = 'a') def __str__(self): return self.company
forms.py
class VendorForm(ModelForm): class Meta: model = Vendor fields = '__all__' exclude = ['created_by', 'branch'] widgets = { 'company':forms.TextInput(attrs={'class':'form-control'}), 'name':forms.TextInput(attrs={'class':'form-control'}), 'phone':forms.TextInput(attrs={'class':'form-control'}), 'email':forms.EmailInput(attrs={'class':'form-control'}), 'gst':forms.TextInput(attrs={'class':'form-control'}), 'pan_no':forms.TextInput(attrs={'class':'form-control'}), 'add_1':forms.TextInput(attrs={'class':'form-control'}), 'add_2':forms.TextInput(attrs={'class':'form-control'}), 'add_3':forms.TextInput(attrs={'class':'form-control'}), 'Remark':forms.Textarea(attrs={'class':'form-control','rows':'2'}), 'status':forms.Select(attrs={'class':'form-control'}), }
views.py
def Add_Vendor(request): # for vendor add msg = "" msg_type = "" branch_id = request.session['branch_id'] branch_data = Branch.objects.get(id = branch_id) form = "" if request.method == "POST": try: form = VendorForm(request.POST) if form.is_valid: vendor_add = form.save(commit=False) vendor_add.created_by = request.user vendor_add.instance.branch = branch_data.id vendor_add.save() form.save_m2m() # for m to m field save msg_type = "success" msg = "Vendor Added." form = VendorForm(initial={'branch':branch_id}) except: msg_type = "error" msg = str(form.errors) print(msg) else: form = VendorForm(initial={'branch':branch_id}) context = { 'form':form, 'branch_data':branch_data, 'msg_type':msg_type, 'msg':msg, 'btn_type':'fa fa-regular fa-plus', 'form_title':'Vendor Form', 'tree_main_title':'Vendor', 'v_url':'vendor_page', 'tree_title':'Add Form', } return render(request, 'base/vendor_master/form_vendor.html',context)
问题分析与修复
现有代码的核心问题:
- 多对多字段赋值方式错误,不能直接给
branch字段赋值ID form.is_valid未加括号,导致表单验证逻辑未执行- 无效的
form.save_m2m()调用(branch字段不在表单中,无需此操作)
修复后的views.py代码:
def Add_Vendor(request): # for vendor add msg = "" msg_type = "" branch_id = request.session['branch_id'] branch_data = Branch.objects.get(id=branch_id) form = "" if request.method == "POST": form = VendorForm(request.POST) if form.is_valid(): # 修复:调用表单验证方法 vendor_add = form.save(commit=False) vendor_add.created_by = request.user vendor_add.save() # 先保存实例,获取主键后再关联多对多字段 vendor_add.branch.add(branch_data) # 修复:用add()方法关联多对多对象 msg_type = "success" msg = "Vendor Added." form = VendorForm() # 重置空表单 else: msg_type = "error" msg = str(form.errors) print(msg) else: form = VendorForm() # 表单已排除branch字段,无需设置initial context = { 'form':form, 'branch_data':branch_data, 'msg_type':msg_type, 'msg':msg, 'btn_type':'fa fa-regular fa-plus', 'form_title':'Vendor Form', 'tree_main_title':'Vendor', 'v_url':'vendor_page', 'tree_title':'Add Form', } return render(request, 'base/vendor_master/form_vendor.html',context)
关键修复说明
- 表单验证:必须调用
form.is_valid()方法,否则表单不会执行验证逻辑 - 多对多关联:多对多字段需要在实例保存后(获取主键),使用
add()方法添加关联对象;若需关联多个分支,可传递多个对象或ID,如vendor_add.branch.add(1, 2, 3) - 无效代码清理:移除
form.save_m2m()和无效的initial设置,因为branch字段已从表单中排除,这些操作无意义
内容的提问来源于stack exchange,提问作者shyam rathod
相关产品推荐
相关产品推荐

