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

Django过滤结果分页异常:切换页码返回全量数据的解决咨询

问题描述

在Django项目中实现数据过滤与分页时遇到异常:提交过滤条件后,第一页能正确展示过滤结果,但点击分页组件的下一页时,页面返回的是未过滤的全量数据,而非过滤后的数据集。

问题原因分析
  1. 请求方式不匹配:过滤条件通过POST请求提交,但分页点击触发的是GET请求,此时后端会进入else分支直接查询全量数据。
  2. 全局变量不可靠:用global get_records_by_date存储过滤后的分页结果,多用户场景下会导致数据混乱,且分页请求无法复用之前的过滤条件。
  3. 分页链接未携带过滤参数:前端分页URL仅包含page参数,未传递过滤条件(日期、复选框状态、下拉选项),后端无法识别这是过滤后的分页请求。
解决方案

步骤1:统一用GET请求处理过滤与分页

将过滤表单的提交方式改为GET,这样过滤条件会作为URL参数传递,分页时可自动携带这些参数,后端统一从request.GET中获取所有参数。

步骤2:重构views.py代码

移除全局变量,每次请求都根据URL参数重新构建查询集再分页:

from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
import datetime

def check_drop_down_status(queryset, drop_down_status):
    # 保留你原本的check_drop_down_status逻辑
    return queryset

def index(request):
    # 从GET请求中获取所有参数
    from_date = request.GET.get("from_date")
    to_date = request.GET.get("to_date")
    new_records = request.GET.get("new_records")
    error_records = request.GET.get("error_records")
    drop_down_status = request.GET.get("field")

    # 初始化查询集为全量数据
    queryset = Scrapper.objects.all()

    # 应用日期范围过滤
    if from_date and to_date:
        try:
            f_date = datetime.datetime.strptime(from_date, '%Y-%m-%d')
            t_date = datetime.datetime.strptime(to_date, '%Y-%m-%d')
            queryset = queryset.filter(start_time__date__range=(f_date, t_date))
        except ValueError:
            # 处理日期格式错误
            pass

    # 处理复选框过滤条件
    filter_conditions = Q()
    if new_records:
        filter_conditions |= Q(new_records__gt=0)
    if error_records:
        filter_conditions |= Q(error_records__gt=0)
    if filter_conditions:
        queryset = queryset.filter(filter_conditions)

    # 处理下拉选项过滤
    queryset = check_drop_down_status(queryset, drop_down_status)

    # 处理分页逻辑
    page = request.GET.get('page', 1)
    paginator = Paginator(queryset, 5)
    try:
        users = paginator.page(page)
    except PageNotAnInteger:
        users = paginator.page(1)
    except EmptyPage:
        users = paginator.page(paginator.num_pages)

    # 将过滤参数传递回模板,保持表单状态
    context = {
        "users": users,
        "from_date": from_date,
        "to_date": to_date,
        "new_records": new_records,
        "error_records": error_records,
        "drop_down_status": drop_down_status
    }
    return render(request, "home.html", context)

步骤3:修改前端home.html模板

  1. 添加GET方式的过滤表单,并保留当前过滤参数状态:
<!-- 过滤表单 -->
<form method="GET" class="mb-4">
    <div class="row">
        <div class="col-md-3">
            <label for="from_date">开始日期:</label>
            <input type="date" name="from_date" id="from_date" value="{{ from_date }}">
        </div>
        <div class="col-md-3">
            <label for="to_date">结束日期:</label>
            <input type="date" name="to_date" id="to_date" value="{{ to_date }}">
        </div>
        <div class="col-md-2">
            <label for="new_records">新记录:</label>
            <input type="checkbox" name="new_records" id="new_records" {% if new_records %}checked{% endif %}>
        </div>
        <div class="col-md-2">
            <label for="error_records">错误记录:</label>
            <input type="checkbox" name="error_records" id="error_records" {% if error_records %}checked{% endif %}>
        </div>
        <div class="col-md-2">
            <label for="field">字段:</label>
            <select name="field" id="field">
                <option value="" {% if not drop_down_status %}selected{% endif %}>全部</option>
                <!-- 替换为你的实际下拉选项 -->
                <option value="scrapper_id" {% if drop_down_status == 'scrapper_id' %}selected{% endif %}>Scrapper ID</option>
            </select>
        </div>
        <div class="col-md-12 mt-2">
            <button type="submit" class="btn btn-primary">过滤</button>
        </div>
    </div>
</form>
  1. 修改分页链接,携带所有过滤参数:
{% if users.has_other_pages %}
    <ul class="pagination">
   {% if users.has_previous %}
     <li><a href="?page={{ users.previous_page_number }}&from_date={{ from_date }}&to_date={{ to_date }}&new_records={{ new_records }}&error_records={{ error_records }}&field={{ drop_down_status }}">«</a></li>
   {% else %}
     <li class="disabled"><span>«</span></li>
   {% endif %}
   {% if users.number|add:'-4' > 1 %}
    <li><a href="?page={{ users.number|add:'-5' }}&from_date={{ from_date }}&to_date={{ to_date }}&new_records={{ new_records }}&error_records={{ error_records }}&field={{ drop_down_status }}">…</a></li>
   {% endif %}
   {% for i in users.paginator.page_range %}
     {% if users.number == i %}
    <li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
    {% elif i > users.number|add:'-5' and i < users.number|add:'5' %}
        <li><a href="?page={{ i }}&from_date={{ from_date }}&to_date={{ to_date }}&new_records={{ new_records }}&error_records={{ error_records }}&field={{ drop_down_status }}">{{ i }}</a></li>
     {% endif %}
   {% endfor %}
   {% if users.has_next %}
     <li><a href="?page={{ users.next_page_number }}&from_date={{ from_date }}&to_date={{ to_date }}&new_records={{ new_records }}&error_records={{ error_records }}&field={{ drop_down_status }}">»</a></li>
   {% else %}
     <li class="disabled"><span>»</span></li>
   {% endif %}
    </ul>
{% endif %}
关键说明
  • 用GET请求统一处理过滤和分页,确保过滤参数通过URL传递,分页时不丢失。
  • 每次请求重新构建查询集,避免全局变量导致的多用户数据冲突。
  • 前端保留过滤参数状态,分页链接携带所有参数,后端能正确返回过滤后的分页数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 04:45:29