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

Django过滤后分页异常问题求助

解决Django中搜索后分页丢失查询条件的问题

看起来你遇到的核心问题是:搜索用POST请求提交,分页跳转用GET请求,导致点击第二页时丢失了搜索参数,视图回到了全量数据的分页。另外你的视图代码有重复逻辑和变量错误,我们一步步来修复:

一、核心问题分析

  1. 搜索用POST提交,分页链接是GET请求,点击分页时不会自动携带POST的搜索参数,所以视图无法获取之前的搜索条件,只能返回所有合同的分页结果。
  2. 视图里分页逻辑重复写了两次,而且有变量错误(比如context里一开始写的queryset1根本没定义)。
  3. 搜索过滤时name__icontains=form['name'].value().upper()是多余的,icontains本身就会忽略大小写匹配,转成大写反而可能导致匹配不到正确结果。

二、分步解决方案

1. 修改搜索表单为GET请求提交

首先把模板里的表单method改成GET,这样搜索参数会出现在URL里,分页时可以携带这些参数:

<!-- customer1.html 里的表单部分 -->
<form method="GET" action="">
    {{ form.as_p }}
    <button type="submit">搜索</button>
</form>

2. 重构视图逻辑,统一处理搜索和分页

去掉重复的分页代码,不管是初始加载还是搜索后,都用同一套分页逻辑,同时从request.GET里获取搜索参数:

# views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .forms import ContractSearchForm

def list_contract(request):
    header = "LIST OF CONTRACT"
    form = ContractSearchForm(request.GET or None)
    queryset = Contracts.objects.all()

    # 处理搜索过滤
    if form.is_valid():
        contract_query = form.cleaned_data.get('contract')
        name_query = form.cleaned_data.get('name')
        if contract_query:
            queryset = queryset.filter(contract__icontains=contract_query)
        if name_query:
            # icontains 已经忽略大小写,不需要转upper
            queryset = queryset.filter(name__icontains=name_query)

    # 处理分页(只写一次即可)
    paginate_by = request.GET.get('paginate_by', 10)
    try:
        paginate_by = int(paginate_by)
    except ValueError:
        paginate_by = 10

    paginator = Paginator(queryset, paginate_by)
    page = request.GET.get('page', 1)
    try:
        page_obj = paginator.page(page)
    except PageNotAnInteger:
        page_obj = paginator.page(1)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)

    context = {
        "form": form,
        "header": header,
        "queryset": page_obj,
        'paginate_by': paginate_by,
    }
    return render(request, "customer1.html", context)

3. 确保分页链接携带所有查询参数

你的param_replace模板标签已经可以处理这个,但要注意模板里的小错误:paginator.num_pages应该是queryset.paginator.num_pages,修正分页部分的模板代码:

{% load my_tags %}

{% if queryset.has_previous %}
<a href="?{% param_replace page=1 %}">First</a>
{% if queryset.previous_page_number != 1 %}
<a href="?{% param_replace page=queryset.previous_page_number %}">Previous</a>
{% endif %}
{% endif %}

Page {{ queryset.number }} of {{ queryset.paginator.num_pages }}

{% if queryset.has_next %}
{% if queryset.next_page_number != queryset.paginator.num_pages %}
<a href="?{% param_replace page=queryset.next_page_number %}">Next</a>
{% endif %}
<a href="?{% param_replace page=queryset.paginator.num_pages %}">Last</a>
{% endif %}

4. 修正表单(可选)

如果不需要export_to_CSV字段在搜索表单里显示,可以调整表单的fields或者用exclude:

# forms.py
class ContractSearchForm(forms.ModelForm):
    use_required_attribute = False
    export_to_CSV = forms.BooleanField(required=False)

    class Meta:
        model = Contracts
        fields = ["contract", "name"]

三、为什么这样改?

  • 用GET提交搜索,参数会保存在URL中,分页时通过param_replace标签自动携带这些参数,确保分页时搜索条件不丢失。
  • 统一分页逻辑,避免重复代码,同时让视图更清晰。
  • 用form.is_valid()来处理表单数据,更符合Django的最佳实践,避免直接访问form['xxx'].value()可能带来的错误。

这样修改后,你点击分页时,URL会变成类似http://127.0.0.1:8000/customer1/?contract=xxx&name=yyy&page=2,视图会根据URL里的搜索参数和分页参数返回正确的结果。

内容的提问来源于stack exchange,提问作者Dinh Truong Anh Phuong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:04:07