Django ModelForm用户未选下拉选项时如何修改外键关联字段值
问题解决方法
首先解释报错原因:你遇到的This QueryDict instance is immutable报错是因为Django默认的request.POST是只读的QueryDict对象,不能直接修改它的键值,而且你在save(commit=False)之后修改form.data也完全无效,此时数据已经被清洗到cleaned_data中,且存储用的实例已经生成,修改表单的data属性不会影响最终入库结果。
另外你原有代码中feedback.sample = sample是错误逻辑:feedback本身就是要保存的Sample模型实例,你的模型里也没有sample这个字段,这行代码直接删掉即可。
1. 调整视图实现逻辑
你的需求是「用户未选择pools下拉选项时自动赋值为id=1的选项,且页面初始加载时无默认高亮」,直接在实例保存阶段处理多对多关系即可,不需要修改表单的输入数据:
def sample_form(request): formulari_mostra = FormulariMostra() if request.method == "POST": formulari_mostra = FormulariMostra(request.POST) if formulari_mostra.is_valid(): feedback = formulari_mostra.save(commit=False) feedback.save() # 判断用户是否未选择pools选项 if not formulari_mostra.cleaned_data['pools'].exists(): # 导入Pool模型,获取id为1的默认实例 from .models import Pool default_pool = Pool.objects.get(id=1) # 直接给实例的多对多字段赋值 feedback.pools.add(default_pool) # 不需要手动调用save_m2m(),我们已经手动处理了多对多关系 messages.success(request, 'Mostra enregistrada correctament!') return render(request, "sample/formulari_mostra.html", {'formulari': formulari_mostra})
2. 补充表单配置(避免校验报错)
你的模型中pools设置了blank=True,但ModelForm默认会把多对多字段设为必填项,需要手动修改为非必填,否则用户不选pools的时候会直接在校验阶段报错,无法进入后续逻辑:
from django import forms from .models import Sample, Pool class FormulariMostra(forms.ModelForm): pools = forms.ModelMultipleChoiceField( queryset=Pool.objects.all(), required=False, verbose_name="Pools" ) class Meta: model = Sample fields = ("name", "sample_id_sex", "pools",)
这个方案完全满足你的需求:初始加载表单时没有设置初始值,下拉框不会有默认高亮;只有当用户真的未选择pools选项时才会自动填充默认值,也绕开了QueryDict不可修改的限制。
内容的提问来源于stack exchange,提问作者Swimming bird
相关产品推荐
相关产品推荐

