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

在__init__中设置字段QuerySet后Django表单验证失败

问题排查与解决方案

问题背景

访问Building页面创建Workorder时,跳转至WorkOrderForm页面。需求为表单仅展示与当前建筑关联的Equipment,而非全部设备。已尝试重写WorkOrderForm的__init__方法设置MultipleChoiceField的queryset,实现了对应建筑设备的显示效果,但提交表单时form.is_valid()验证失败,且无错误信息输出。

核心原因

  1. POST请求未传入建筑参数:渲染表单时传入了building参数过滤设备,但提交表单创建WorkOrderForm实例时,未传递该参数,导致equipment字段的queryset被重置为所有设备。此时用户选择的设备不在默认queryset中,触发验证失败。
  2. 多余的clean调用:form.is_valid()会自动执行表单的clean流程,手动调用form.clean()属于重复操作,可能干扰验证逻辑。
  3. 多对多字段未正确保存:使用commit=False保存模型实例后,多对多关系不会自动保存,需手动调用save_m2m()完成关联。

修复步骤

  1. POST请求创建表单时,传入当前建筑的building_code参数,保证验证阶段的queryset与渲染阶段一致。
  2. 移除form.clean()的手动调用。
  3. 保存模型实例后,调用form.save_m2m()处理多对多字段关联。

修正后代码

Forms.py(补充空值判断)

class WorkOrderForm(ModelForm):
    class Meta:
        model = WorkOrder
        fields = '__all__'
        widgets = {
            "issue_Date": DatePickerInput(),
            "completion_Date": DatePickerInput(),
        }
    
    def __init__(self, *args, **kwargs):
        building = kwargs.pop('building', None)
        super(WorkOrderForm, self).__init__(**kwargs)
        # 避免building为None时触发无效过滤
        if building:
            self.fields['equipment'].queryset = Equipment.objects.filter(building__location_Code=building)

Views.py(关键修改)

def CreateWorkOrder(request, building_code):
    if building_code == "none":
        workOrderForm = WorkOrderForm()
        associatedCostsForm = AssociatedCostsForm()
        context = {
            'workOrderForm': workOrderForm,
            'associatedCostsForm': associatedCostsForm,
        }
    else:
        building = BuildingDetail.objects.get(location_Code=building_code)
        currentTenant = building.current_Tenant
        workOrderForm = WorkOrderForm(building=building_code, initial={
            'building_Code': building,
            'tenant': currentTenant})
        associatedCostsForm = AssociatedCostsForm()
        context = {
            'workOrderForm': workOrderForm,
            'associatedCostsForm': associatedCostsForm,
            'building_code': building_code,
            'building': building,
        }

    if request.method == "POST":
        # 关键:创建表单时传入building_code参数
        form = WorkOrderForm(request.POST, building=building_code)
        if 'submit-workorder' in request.POST:
            if form.is_valid():
                workorder = form.save(commit=False)
                workorder.save()
                # 保存多对多关系
                form.save_m2m()
                print("You have submitted a Work Order.")
                return redirect('view_building', workorder.building_Code.location_Code)
            else:
                print(form.errors)

    return render(request, 'workorders\\workorder_form.html', context)

额外优化建议

  • 处理BuildingDetail.DoesNotExist异常:当building_code无效时,返回404页面,避免程序崩溃。
  • 表单验证失败时,将错误信息传递到模板,方便用户直观查看问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 23:50:34