Django dynamic formset提交时仅保存最后一条数据问题求助
问题根因
你的代码存在3处核心错误,共同导致了formset仅能识别并保存最后一行数据:
1. 前端模板HTML语法错误
你在循环渲染form行的时候提前闭合了<tr>标签,所有表单字段都脱离了对应行的作用域,导致多行行的表单name属性冲突,仅最后一行的值能被正确提交:
<!-- 错误写法 --> <tr id="{{ form.prefix }}-row"></tr> <td>...</td> <td>...</td> </tr>
修复为:
<!-- 正确写法,去掉多余的闭合tr标签 --> <tr id="{{ form.prefix }}-row"> <td> {% for fld in form.hidden_fields %}{{ fld }}{% endfor %} {% if form.instance.pk %}{{ form.DELETE }}{% endif %} {{ form.med_name}} </td> <td>{{ form.dose }}</td> </tr>
两个子表单的行渲染部分都要做同样修改。
2. formset前缀不匹配
inlineformset_factory生成的formset默认前缀为子模型小写+_set,也就是currentmed_set和pastmed_set,但你在jquery.formset的初始化代码里写的前缀是current_meds和past_meds,二者不匹配导致动态增删的行生成的name属性不符合后端formset的解析规则,新增行全部无法被识别:
// 错误写法 $(function() { $('#currentmeds_table tbody tr').formset({ prefix: 'current_meds' }) }); $(function() { $('#pastmeds_table tbody tr').formset({ prefix: 'past_meds' }) });
修复为:
// 正确写法,用模板变量渲染前缀避免手动拼写错误 $(function() { $('#currentmeds_table tbody tr').formset({ prefix: '{{ currentmed_formset.prefix }}' }) }); $(function() { $('#pastmeds_table tbody tr').formset({ prefix: '{{ pastmed_formset.prefix }}' }) });
3. 视图逻辑缺陷
你目前的post方法没有处理表单验证失败的场景,同时get方法里的PatientForm没有实例化,会导致渲染异常:
get方法修复:
def get(self, *args, **kwargs): # 实例化表单,不要直接传类 patient_form = PatientForm() currentmed_formset = CurrentmedFormSet(queryset=CurrentMed.objects.none()) pastmed_formset = PastmedFormSet(queryset=PastMed.objects.none()) return self.render_to_response({'currentmed_formset': currentmed_formset, 'pastmed_formset': pastmed_formset, 'patient_form': patient_form})
post方法修复:
def post(self, *args, **kwargs): form = PatientForm(data=self.request.POST) currentmed_formset = CurrentmedFormSet(data=self.request.POST) pastmed_formset = PastmedFormSet(data=self.request.POST) # 所有表单都验证通过才保存 if form.is_valid() and currentmed_formset.is_valid() and pastmed_formset.is_valid(): patient_instance = form.save() for med in currentmed_formset.save(commit=False): med.patient = patient_instance med.save() for med in pastmed_formset.save(commit=False): med.patient = patient_instance med.save() return redirect(reverse( 'patient:treatment_detail', kwargs={"patient_id": patient_instance.patient_id})) # 验证失败返回表单页,保留用户输入和错误提示 return self.render_to_response({'currentmed_formset': currentmed_formset, 'pastmed_formset': pastmed_formset, 'patient_form': form})
注:如果你的Patient模型没有定义sex、age、diagnosis字段,需要先补充对应的模型字段,否则PatientForm会初始化失败。
修改完成后即可正常保存所有formset行的数据。
内容的提问来源于stack exchange,提问作者RobMcC
相关产品推荐
相关产品推荐

