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

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)

关键修改点

  1. 提前初始化表单集:不管请求方法是GET还是POST,先为formset和formset_paused赋值默认的表单集实例,确保变量始终存在。
  2. 增加表单验证:在调用save()前添加is_valid()检查,避免非法数据存入数据库,这是Django表单处理的最佳实践。
  3. 逻辑更清晰:POST分支仅在匹配对应表单类型时,才重新实例化表单集并处理提交,其余情况保持默认初始化的表单集。

模板代码说明

模板部分无需修改,两个表单的name和id区分明确,不会互相干扰,可正常使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:57:16