You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 16:45:03