Django同一页面展示双筛选查询列表报错求解
问题描述
在Django页面中展示两个营销活动列表:一个显示is_active=True的活跃活动,另一个显示is_active=False的暂停活动。当前代码触发UnboundLocalError,错误信息为:
UnboundLocalError at / local variable 'formset_paused' referenced before assignment
添加第二个查询和表格前功能正常,以下是原代码:
原views.py代码
def home_view(request): #campaigns in progress queryset = Campaign.objects.filter(is_active=True, completion_percent__lt=100) if request.method == "POST": form_type = request.POST.get('id') if form_type == 'campaign_status': formset = CampaignStatusFormSet( request.POST, request.FILES, queryset=queryset, ) formset.save() else: formset = CampaignStatusFormSet(queryset=queryset) campaigns_and_forms = list(zip(queryset, formset)) #paused campaigns queryset_paused = Campaign.objects.filter(is_active=False, completion_percent__lt=100) if request.method == "POST": form_type_paused = request.POST.get('id_paused') if form_type_paused == 'campaign_status_paused': formset_paused = CampaignStatusFormSet( request.POST, request.FILES, queryset=queryset_paused, ) formset_paused.save() else: formset_paused = CampaignStatusFormSet(queryset=queryset_paused) paused_campaigns_and_forms = list(zip(queryset_paused, formset_paused)) context = { 'formset': formset, 'formset_paused': formset_paused, 'campaigns_and_forms': campaigns_and_forms, 'paused_campaigns_and_forms': paused_campaigns_and_forms, } return render(request, 'campaigns_in_progress.html', context)
原模板代码
<table class="table table-striped table-hover table-bright table-bordered align-middle"> <thead> <tr> <th scope="col">ID</th> <th scope="col">Nazwa</th> <th scope="col">Temat</th> <th scope="col">Nadawca</th> <th scope="col">Procent Realizacji</th> <th scope="col">Start Kampani</th> <th scope="col">Stan</th> </tr> </thead> <tbody> <form method="post" id="campaign_status"> {% csrf_token %} <input type='hidden' value='campaign_status' name='id'> {{ formset.management_form }} {% for campaign, form in campaigns_and_forms %} <tr> <td>{{ campaign.campaign_id }}</td> <td>{{ campaign.name }}</td> <td>{{ campaign.topic }}</td> <td>{{ campaign.sender }}</td> <td> <div class="progress"> <div class="progress-bar" role="progressbar" style="width: {{campaign.completion_percent}}%;" aria-valuenow="{{campaign.completion_percent}}" aria-valuemin="0" aria-valuemax="100">{{campaign.completion_percent}}%</div> </div> </td> <td>{{ campaign.start_date }}</td> <td>{{ form.as_p }}</td> </tr> {% endfor %} </form> </tbody> </table> <h4>Kampanie zatrzymane</h4> <table class="table table-striped table-hover table-bright table-bordered align-middle"> <thead> <tr> <th scope="col">ID</th> <th scope="col">Nazwa</th> <th scope="col">Temat</th> <th scope="col">Nadawca</th> <th scope="col">Procent Realizacji</th> <th scope="col">Start Kampani</th> <th scope="col">Stan</th> </tr> </thead> <tbody> <form method="post" id="campaign_status_paused"> {% csrf_token %} <input type='hidden' value='campaign_status_paused' name='id_paused'> {{ formset_paused.management_form }} {% for campaign, form in paused_campaigns_and_forms %} <tr> <td>{{ campaign.campaign_id }}</td> <td>{{ campaign.name }}</td> <td>{{ campaign.topic }}</td> <td>{{ campaign.sender }}</td> <td> <div class="progress"> <div class="progress-bar" role="progressbar" style="width: {{campaign.completion_percent}}%;" aria-valuenow="{{campaign.completion_percent}}" aria-valuemin="0" aria-valuemax="100">{{campaign.completion_percent}}%</div> </div> </td> <td>{{ campaign.start_date }}</td> <td>{{ form.as_p }}</td> </tr> {% endfor %} </form> </tbody> </table>
问题原因与修复方案
错误原因
当提交活跃活动表单的POST请求时,代码会进入暂停活动的POST判断分支,但此时form_type_paused不等于campaign_status_paused,导致formset_paused变量未被赋值。而后续代码需要使用这个变量,因此触发未绑定局部变量的错误。
同时,原代码中活跃活动的formset也存在相同的潜在问题——如果POST请求不是针对活跃表单,formset同样会未定义。
修复后的views.py代码
def home_view(request): # 活跃营销活动 queryset = Campaign.objects.filter(is_active=True, completion_percent__lt=100) # 先初始化默认表单集,避免POST分支未赋值的情况 formset = CampaignStatusFormSet(queryset=queryset) if request.method == "POST": form_type = request.POST.get('id') if form_type == 'campaign_status': # 仅在对应表单提交时重新实例化并处理 formset = CampaignStatusFormSet( request.POST, request.FILES, queryset=queryset, ) # 增加表单验证,确保数据合法再保存 if formset.is_valid(): formset.save() campaigns_and_forms = list(zip(queryset, formset)) # 暂停营销活动 queryset_paused = Campaign.objects.filter(is_active=False, completion_percent__lt=100) # 同样先初始化默认表单集 formset_paused = CampaignStatusFormSet(queryset=queryset_paused) if request.method == "POST": form_type_paused = request.POST.get('id_paused') if form_type_paused == 'campaign_status_paused': formset_paused = CampaignStatusFormSet( request.POST, request.FILES, queryset=queryset_paused, ) if formset_paused.is_valid(): formset_paused.save() paused_campaigns_and_forms = list(zip(queryset_paused, formset_paused)) context = { 'formset': formset, 'formset_paused': formset_paused, 'campaigns_and_forms': campaigns_and_forms, 'paused_campaigns_and_forms': paused_campaigns_and_forms, } return render(request, 'campaigns_in_progress.html', context)
关键修改点
- 提前初始化表单集:不管请求方法是GET还是POST,先为
formset和formset_paused赋值默认的表单集实例,确保变量始终存在。 - 增加表单验证:在调用
save()前添加is_valid()检查,避免非法数据存入数据库,这是Django表单处理的最佳实践。 - 逻辑更清晰:POST分支仅在匹配对应表单类型时,才重新实例化表单集并处理提交,其余情况保持默认初始化的表单集。
模板代码说明
模板部分无需修改,两个表单的name和id区分明确,不会互相干扰,可正常使用。
内容的提问来源于stack exchange,提问作者low_ratio
相关产品推荐
相关产品推荐

