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

Django模板页面重载后如何保留筛选器选中值?

Django页面重载后保留筛选器选中值的解决方案

问题背景

我在Django模板中尝试实现页面重载后保留筛选器的选中值,但下面两种写法都无效:

第一种模板代码

<label for="structDivisions">Structural divisions</label>
<select id="structDivisions" class="form-select form-select-sm"
        name="struct_division">
    {% for SD in struct_divisions %}
        <option value="{{ SD.id }}" {% if SD.id == struct_division.id %}
                selected {% endif %}>{{ SD }}</option>
    {% endfor %}
</select>

第二种模板代码

<label for="structDivisions">Structural divisions</label>
<select id="structDivisions" class="form-select form-select-sm"
        name="struct_division">
    {% for SD in struct_divisions %}
        <option value="{{ SD }}" {% if SD == struct_division.select %}
                selected {% endif %}>{{ SD }}</option>
    {% endfor %}
</select>

视图函数代码(筛选功能正常但无法保留选中值)

def ReportsFilterView(request):
    user = get_current_user(request)
    qs = CompletedWork.objects.filter(checked_by_head=True).filter(
        Q(worker__struct_division__head=user) |
        Q(worker__struct_division__management_unit__head=user) |
        Q(worker__struct_division__curator=user) |
        Q(worker__struct_division__management_unit__curator=user)
    )
    struct_divisions = StructuralDivisions.objects.filter(
        Q(head=user) |
        Q(management_unit__head=user) |
        Q(curator=user) |
        Q(management_unit__curator=user)
    )
    workers = CustomUser.objects.filter(
        Q(struct_division__head=user) |
        Q(struct_division__management_unit__head=user) |
        Q(struct_division__curator=user) |
        Q(struct_division__management_unit__curator=user)
    )
    workstype = WorksType.objects.filter(
        Q(available_to__head=user) |
        Q(available_to__curator=user)
    ).distinct()

    work_notes_contains_query = request.GET.get('work_notes_contains')
    work_scope_min = request.GET.get('work_scope_min')
    work_scope_max = request.GET.get('work_scope_max')
    period_min = request.GET.get('period_min')
    period_max = request.GET.get('period_max')
    struct_division = request.GET.get('struct_division')

    # special for worker
    worker = request.GET.get('worker')

    if worker and worker != 'Choose...':
        middle_name = None

        try:
            last_name, first_name, middle_name = worker.split()
            try:
                worker_get_id = CustomUser.objects.get(last_name=last_name,
                                                    first_name=first_name,
                                                    middle_name=middle_name)
            except ValueError:
                worker_get_id = None

        except ValueError:
            last_name, first_name = worker.split()
            worker_get_id = CustomUser.objects.get(last_name=last_name,
                                                first_name=first_name)


    work_done = request.GET.get('work_done')

    if is_valid_query_param(work_notes_contains_query):
        qs = qs.filter(work_notes__icontains=work_notes_contains_query)

    if is_valid_query_param(work_scope_min):
        qs = qs.filter(work_scope__gte=work_scope_min)

    if is_valid_query_param(work_scope_max):
        qs = qs.filter(work_scope__lte=work_scope_max)

    if is_valid_query_param(period_min):
        qs = qs.filter(period__date__gte=period_min)

    if is_valid_query_param(period_max):
        qs = qs.filter(period__date__lte=period_max)

    if is_valid_query_param(struct_division) and struct_division != 'Choose...':
        qs = qs.filter(worker__struct_division__name=struct_division)

    if worker:
        if is_valid_query_param(worker) and worker != 'Choose...':
            qs = qs.filter(worker=worker_get_id)

    if is_valid_query_param(work_done) and work_done != 'Choose...':
        qs = qs.filter(work_done__name=work_done).filter(
            Q(worker__struct_division__head=user) |
            Q(worker__struct_division__management_unit__head=user) |
            Q(worker__struct_division__curator=user) |
            Q(worker__struct_division__management_unit__curator=user)
        )

    context = {
        'queryset': qs,
        'struct_divisions': struct_divisions,
        'workers': workers,
        'workstype': workstype,
    }

    if 'button_export' in request.GET:
        return export_report(request)

    return render(request, 'reports_related_struct_unit.html', context)

解决方案

核心问题是未将当前选中的筛选参数传入模板上下文,同时模板中的判断逻辑存在类型不匹配的问题,按以下步骤修改即可解决:

步骤1:更新视图函数,传递筛选参数到上下文

在视图的context字典中,添加所有当前获取到的GET筛选参数:

context = {
    'queryset': qs,
    'struct_divisions': struct_divisions,
    'workers': workers,
    'workstype': workstype,
    # 新增:传递所有筛选参数到模板
    'work_notes_contains': work_notes_contains_query,
    'work_scope_min': work_scope_min,
    'work_scope_max': work_scope_max,
    'period_min': period_min,
    'period_max': period_max,
    'selected_struct_division': struct_division,
    'selected_worker': worker,
    'selected_work_done': work_done,
}

步骤2:修正模板下拉框的选中判断逻辑

针对struct_division下拉框,根据传入的selected_struct_division值判断选中状态,注意处理类型匹配问题:

情况1:下拉框选项值用SD.id

request.GET获取的是字符串类型,而SD.id是整数,需要转成字符串再比较:

<label for="structDivisions">Structural divisions</label>
<select id="structDivisions" class="form-select form-select-sm"
        name="struct_division">
    <option value="Choose...">Choose...</option>
    {% for SD in struct_divisions %}
        <option value="{{ SD.id }}" {% if SD.id|stringformat:"s" == selected_struct_division %}
                selected {% endif %}>{{ SD }}</option>
    {% endfor %}
</select>

情况2:下拉框选项值用SD.name(和视图中筛选逻辑匹配)

直接比较字符串即可:

<label for="structDivisions">Structural divisions</label>
<select id="structDivisions" class="form-select form-select-sm"
        name="struct_division">
    <option value="Choose...">Choose...</option>
    {% for SD in struct_divisions %}
        <option value="{{ SD.name }}" {% if SD.name == selected_struct_division %}
                selected {% endif %}>{{ SD }}</option>
    {% endfor %}
</select>

步骤3:其他筛选控件的适配示例

  • 文本输入框:直接设置value属性
<input type="text" name="work_notes_contains" value="{{ work_notes_contains|default:'' }}">
  • 数值范围输入框:
<input type="number" name="work_scope_min" value="{{ work_scope_min|default:'' }}">
<input type="number" name="work_scope_max" value="{{ work_scope_max|default:'' }}">

额外优化:统一处理默认值

在视图中给参数设置默认值,避免模板出现None:

struct_division = request.GET.get('struct_division', 'Choose...')
worker = request.GET.get('worker', 'Choose...')
# 其他参数同理设置默认值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:05:21