You need to enable JavaScript to run this app. Django UpdateView中Formset无法保存 校验提示id字段必填问题求助
优惠活动
大模型
产品
解决方案
定价
更多

Django UpdateView中Formset无法保存 校验提示id字段必填问题求助

问题根因

你遇到的{'id': ['This field is required.']}报错,核心原因是模板中没有渲染Formset自带的主键隐藏字段。Django的ModelFormset/InlineFormset在更新场景下,需要通过这个隐藏的id字段定位到要修改的已有子数据,缺失该字段时Django无法关联到原有数据,就会抛出id必填的校验错误。

解决步骤

1. 模板层面修改(必做)

首先确认你的模板中已经添加了两处必要的formset渲染逻辑:

  • 必须在所有formset表单项之前渲染formset.management_form,Django通过该组件统计表单总数、初始表单数量等元数据
  • 遍历formset的每个子表单时,必须渲染form.id这个隐藏字段,不需要用户修改,只需要提交时带上值即可

模板示例代码:

<form method="post">
    {% csrf_token %}
    <!-- 父表单字段 -->
    {{ form.as_p }}

    <!-- Formset管理表单,必加 -->
    {{ formset.management_form }}
    {% for sub_form in formset %}
        <!-- 主键隐藏字段,必加 -->
        {{ sub_form.id }}
        <!-- 你自定义的子表单项 -->
        <div>
            {{ sub_form.item_name.label }}
            {{ sub_form.item_name }}
            {{ sub_form.item_name.errors }}
        </div>
        <!-- 如果开启了can_delete参数,也要渲染删除字段:{{ sub_form.DELETE }} -->
    {% endfor %}

    <button type="submit">提交</button>
</form>

2. 后端代码优化(可选,避免冗余逻辑)

你当前的代码中存在重复实例化formset的问题:post方法中手动实例化了一次formset,调用get_context_data时又会实例化一次,完全可以删掉post方法中冗余的实例化逻辑,简化后的代码如下:

class JournalEntryUpdateView(UpdateView):
    model = JournalEntry
    template_name = 'add-journal-entry.html'
    success_url = reverse_lazy('index')
    form_class = JournalEntryForm

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        if self.request.POST:
            context['formset'] = journal_entry_formset(self.request.POST, instance=self.object)
        else:
            context['formset'] = journal_entry_formset(instance=self.object)
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        formset = context['formset']
        if formset.is_valid():
            self.object = form.save()
            formset.save()
            return super().form_valid(form)
        else:
            return self.form_invalid(form)

注:原代码中formset.instance = self.object是冗余逻辑,实例化formset时已经传入了instance参数,不需要重复赋值。

内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 04:18:02