Django内联表单集更新验证失败,返回空列表错误
问题描述
创建功能运行正常,但更新功能出现异常:每个内联表单集都会返回1个空列表[]形式的错误。相关代码及打印输出如下:
forms.py
StructureFormset = inlineformset_factory(Plan, Structure, fields = ( 'material_type', 'weight', 'thickness', 'provider' ), extra=0, can_delete=True ) TestFormset = inlineformset_factory(Plan, Test, fields=( 'essay', 'critic', 'spec' ), extra = 0, can_delete=True ) class PlanForm(ModelForm): class Meta: model = Plan fields = ( 'format', 'pc', 'revission', 'rev_date', 'client', 'product', 'gp_code', 'code', 'observation', 'continuation', 'dispatch_conditions', 'elaborator', 'reviewer' ) localized_fields=('rev_date',)
views.py
def editPlan(request, pk): plan = Plan.objects.get(id = pk) form = PlanForm(instance = plan) sformset = StructureFormset(instance=plan) tformset = TestFormset(instance=plan) context = { 'form': form, 'sformset': sformset, 'tformset': tformset } if request.method == 'POST': print('----------------------------request----------------------------') print(request.POST) form = PlanForm(request.POST, instance = plan) sformset = StructureFormset(request.POST, instance=plan, prefix='structure') tformset = TestFormset(request.POST, instance=plan, prefix='test') if form.is_valid() and sformset.is_valid() and tformset.is_valid(): print('-----------------------is valid-----------------------') form.save() instances = sformset.save(commit=False) for instance in instances: sformset.save_m2m() instance.save() tformset.save() return redirect('/plans/') else:#printing errors print('-----------------------is not valid-----------------------') print(sformset.total_error_count()) print(sformset.errors) print(tformset.total_error_count()) print(tformset.errors) return render(request, 'home/plan_forms.html', context)
template.html
{{ tformset.management_form }} <table> <thead> <tr> <th>Essay</th> <th> <abb title="Critical Variable">Crit.</abb> </th> <th>Spec</th> {% if tformset.instance.pk %} <th class="text-center px-1 col-1 pb-2"> <i class="material-icons">delete</i> </th> {% endif %} </tr> </thead> <tbody id="tform_set"> <!--Test form goes here--> {% if tformset %} {% for tt in tformset %} {% for hidden in tt.hidden_fields %} {{ hidden }} {% endfor %} <tr> <td> {{ tt.essay }} </td> <td class="px-1 col-1 text-center justify-content-center"> {{ tt.critic }} </td> <td> {{ tt.spec }} </td> <td> {% if tt.instance.pk %}{{ tt.DELETE }}{% endif %} </td> </tr> {% endfor %} {% endif %} </tbody> <tbody id="tempty_form" style="display:none !important;"> <tr> <td> {{ tformset.empty_form.essay }} </td> <td> {{ tformset.empty_form.critic }} </td> <td> {{ tformset.empty_form.spec }} </td> </tr> </tbody> </table> {{ sformset.management_form }} <table> <thead> <tr> <th>Material</th> <th>Weight (g/m²)</th> <th>Thickness (μ)</th> <th>Provider</th> {% if sformset.instance.pk %} <th class="text-center col-1 px-1 pb-2"> <i class="material-icons">delete</i> </th> {% endif %} </tr> </thead> <tbody id="sform_set"> <!--Structure form goes here--> {% if sformset %} {% for ss in sformset %} {% for hidden in ss.hidden_fields %} {{ hidden }} {% endfor %} <tr> <td> {{ ss.material_type }} </td> <td> {{ ss.weight }} </td> <td> {{ ss.thickness }} </td> <td> {{ ss.provider }} </td> <td> {% if ss.instance.pk %}{{ ss.DELETE }}{% endif %} </td> </tr> {% endfor %} {% endif %} </tbody> <tbody id="sempty_form" style="display:none !important;"> <tr> <td> {{ sformset.empty_form.material_type }} </td> <td> {{ sformset.empty_form.weight }} </td> <td> {{ sformset.empty_form.thickness }} </td> <td> {{ sformset.empty_form.provider }} </div> </td> </tr> </tbody> </table>
打印输出
-----------------------is not valid----------------------- 1 [] 1 []
解决方案
问题根源
GET请求初始化表单集时未指定prefix,但POST请求时添加了prefix='structure'和prefix='test',导致前后表单集的字段命名不匹配,无法正确识别POST数据,进而触发空验证错误。另外save_m2m()的调用位置错误。
修复步骤
- 统一表单集的prefix:在GET请求初始化表单集时,添加与POST一致的prefix参数:
# 修改views.py中GET部分的表单集初始化代码 sformset = StructureFormset(instance=plan, prefix='structure') tformset = TestFormset(instance=plan, prefix='test')
- 修正save_m2m()调用位置:
save_m2m()是针对整个表单集的方法,不需要在循环内部调用,应放在实例保存循环之后:
# 修改sformset保存的代码块 instances = sformset.save(commit=False) for instance in instances: instance.save() sformset.save_m2m()
验证
修改后重新测试更新功能,表单集将能正确识别POST提交的数据,验证通过后正常保存更新。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

