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
相关产品推荐
相关产品推荐

