Django Formset带Queryset无法保存:需实现数据回显与更新
Django Formset 加载并保存数据的解决方案
问题根源
你代码的核心问题是:POST请求时没有把Formset和原主模型实例(form_main)绑定,同时MainForm也没关联到原实例,导致没法更新已有数据;而GET请求时的绑定是对的,所以能正常回显数据。
修复后的完整代码
from django.shortcuts import get_object_or_404, render from django.forms import inlineformset_factory # 关联模型用inlineformset更省心 # 先定义关联模型的Formset(用inlineformset_factory比modelformset更适合主从模型场景) MyFormsetForm = inlineformset_factory( MyModel, # 主模型(就是你用get_object_or_404获取的MyModel) MyRelatedModel, # 和主模型关联的子模型(Formset对应的数据表) fields=('item', 'other_field'), # 替换成你的实际字段 extra=1, # 允许用户添加新条目 can_delete=True # 如果需要允许删除已有条目,开启这个 ) def your_view_name(request, pk): # 获取主模型实例 form_main = get_object_or_404(MyModel, pk=pk) # 只加载和当前主实例关联的子模型数据 queryset = MyRelatedModel.objects.filter(main_model=form_main).order_by('item') if request.method == 'POST': # POST时必须绑定主实例和查询集,同时传入POST数据 form = MainForm(request.POST, instance=form_main) formset = MyFormsetForm(request.POST, instance=form_main, queryset=queryset) if form.is_valid() and formset.is_valid(): # 先保存主表单(如果需要更新主模型的字段) form.save() # 保存Formset:inlineformset会自动关联主模型,不用手动绑定 formset.save() else: # GET请求正常绑定实例和查询集,回显已有数据 form = MainForm(instance=form_main) formset = MyFormsetForm(instance=form_main, queryset=queryset) return render(request, 'your_template.html', {'form': form, 'formset': formset})
关键修复点
- POST请求必须绑定instance和queryset:Formset需要知道要更新哪些已有数据,以及归属哪个主模型,不然会默认创建新的子模型数据,而不是更新原有数据。
- MainForm绑定instance:避免POST时创建新的MyModel实例,而是更新你从数据库获取的form_main。
- 用inlineformset_factory替代modelformset_factory:如果是主从关联的模型,inlineformset会自动处理子模型和主模型的外键关联,不用手动写代码绑定,更不容易出错。
- 模板必须渲染management_form:在模板里要加上
{{ formset.management_form }},Django靠这个识别Formset的条目数量,没加的话Formset数据根本存不进去。
额外提示
如果你之前用的是modelformset_factory,也能修复,但需要手动给子模型实例绑定主模型:
# 保存Formset时的代码 instances = formset.save(commit=False) for instance in instances: instance.main_model = form_main # 替换成你的外键字段名 instance.save() # 处理删除的条目 for deleted_form in formset.deleted_forms: deleted_form.save()
内容的提问来源于stack exchange,提问作者Barak
相关产品推荐
相关产品推荐

