Django过滤后分页异常问题求助
解决Django中搜索后分页丢失查询条件的问题
看起来你遇到的核心问题是:搜索用POST请求提交,分页跳转用GET请求,导致点击第二页时丢失了搜索参数,视图回到了全量数据的分页。另外你的视图代码有重复逻辑和变量错误,我们一步步来修复:
一、核心问题分析
- 搜索用
POST提交,分页链接是GET请求,点击分页时不会自动携带POST的搜索参数,所以视图无法获取之前的搜索条件,只能返回所有合同的分页结果。 - 视图里分页逻辑重复写了两次,而且有变量错误(比如
context里一开始写的queryset1根本没定义)。 - 搜索过滤时
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
相关产品推荐
相关产品推荐

