Django ModelForm ce_hostname下拉按订单过滤为空问题
问题原因
当前下拉框空白的核心原因是表单初始化与参数赋值顺序错误:
- 视图中先执行
Cx_BaseForm()实例化,这一步已经跑完了表单__init__方法里的ce_hostname查询集过滤逻辑,此时self.instance.order_reference默认是空值None,过滤出来的Ce_Base结果为空集 - 实例化完成后才给
cx_base_form.instance.order_reference赋值,这个后置操作不会重新触发下拉框查询集的计算,所以下拉框始终显示空白 - 硬编码
order_reference='1'时过滤逻辑不依赖未赋值的instance属性,所以能正常运行
修复方案
修改forms.py
不要从self.instance取订单对象做过滤,改成通过初始化参数显式传入当前订单,避免时序问题:
class Cx_BaseForm(ModelForm): class Meta: model = Cx_Base fields = ['cx_hostname', 'new', 'ce_hostname', 'location', 'manged_module_model', 'slot'] def __init__(self, *args, **kwargs): # 从初始化参数中弹出提前传入的current_order,避免传给父类ModelForm触发参数错误 current_order = kwargs.pop('current_order', None) super(Cx_BaseForm, self).__init__(*args, **kwargs) # 拿到传入的订单对象后再执行过滤 if current_order is not None: self.fields['ce_hostname'].queryset = Ce_Base.objects.filter(order_reference=current_order) else: # 兜底逻辑,未传订单时返回空查询集,避免泄露全量CE主机数据 self.fields['ce_hostname'].queryset = Ce_Base.objects.none()
修改views.py
不管是GET请求渲染空表单,还是POST请求处理提交,实例化表单时都直接传入当前订单对象,保证表单初始化阶段就能拿到过滤参数:
@login_required def addCX_Base(request, pk_test): order = Order.objects.get(id=pk_test) # GET请求实例化表单时直接传入current_order参数 cx_base_form = Cx_BaseForm(current_order=order) if request.method == 'POST': # POST请求实例化表单时也要传current_order,避免表单校验失败重渲染时下拉框再次变空 cx_base_form = Cx_BaseForm(request.POST, current_order=order) # 保留实例绑定订单的逻辑,保证数据保存时关联关系正确 cx_base_form.instance.order_reference = order if request.POST.get("new") == "on": print(request.POST.get("new")) else: for managed_module in inventory["managed_modules"]: print(managed_module["model"]) model = request.POST.get("manged_module_model") print(model) if model == managed_module["model"]: print(managed_module["l2_ports"]) cx_base_form.instance.l2_interfaces = managed_module["l2_ports"] if cx_base_form.is_valid(): cx_base_form.save() return redirect('/') else: print("Form is not valid") context = {'cx_base_form':cx_base_form} return render(request, 'orchestration/cx_base_form.html', context)
注意:不要依赖「先实例化表单再给instance赋值」的方式传递动态过滤参数,因为
__init__里的字段配置逻辑在实例化时就已经执行完成,后置修改instance属性不会回溯更新已经生成的字段配置。所有动态过滤需要的参数,都要在实例化表单时通过kwargs显式传入。
内容的提问来源于stack exchange,提问作者Jonathan E
相关产品推荐
相关产品推荐

