Django类视图分页异常:搜索查询翻页后丢失致无结果
问题原因分析
嘿,我来帮你搞定这个分页问题!你遇到的核心问题是分页链接没有携带搜索查询参数q:当点击下一页时,请求URL里只保留了page=2,丢失了关键的q=love参数。这导致视图中query为空,触发了queryset_list = Song.objects.none()的逻辑——空的查询集自然无法分页,所以才会抛出"Invalid page (2): That page contains no results"的错误。
解决方案
我们需要修改分页链接,让它在跳转时保留搜索的q参数,下面提供两种实用的实现方式:
方式一:直接在模板中拼接查询参数
这是最直接的修改方式,只需调整search.html里的分页链接,把当前的q参数添加到每个分页URL中:
{% if is_paginated %} <ul class="pagination"> {% if page_obj.has_previous %} <li><a href="?q={{ request.GET.q }}&page={{ page_obj.previous_page_number }}">«</a></li> {% else %} <li class="disabled"><span>«</span></li> {% endif %} {% for i in paginator.page_range %} {% if page_obj.number == i %} <li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li> {% else %} <li><a href="?q={{ request.GET.q }}&page={{ i }}">{{ i }}</a></li> {% endif %} {% endfor %} {% if page_obj.has_next %} <li><a href="?q={{ request.GET.q }}&page={{ page_obj.next_page_number }}">»</a></li> {% else %} <li class="disabled"><span>»</span></li> {% endif %} </ul> {% endif %}
这样每次点击分页按钮时,URL都会带上q参数,视图就能正确获取搜索条件,返回对应的查询集完成分页。
方式二:在视图中传递查询参数到模板(更优雅)
如果你想让代码结构更清晰,可以在视图里把查询参数存入上下文,再在模板中调用:
1. 更新views.py中的Search视图
添加get_context_data方法,把搜索查询参数传递到模板:
from django.views import generic from .models import Album, Song from django.db.models import Q class Search(generic.ListView): template_name = 'music/search.html' paginate_by = 5 def get_queryset(self, *args, **kwargs): queryset_list = Song.objects.all() query = self.request.GET.get('q') if query: queryset_list = queryset_list.filter( Q(song_title__icontains=query)| Q(file_type__icontains=query) ).distinct() if not query: queryset_list = Song.objects.none() return queryset_list # 注意你之前写了两个重复的return,删掉一个即可 def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 把搜索查询参数存入上下文,方便模板调用 context['search_query'] = self.request.GET.get('q', '') return context
2. 修改search.html中的分页链接
用上下文里的search_query代替直接调用request.GET.q:
{% if is_paginated %} <ul class="pagination"> {% if page_obj.has_previous %} <li><a href="?q={{ search_query }}&page={{ page_obj.previous_page_number }}">«</a></li> {% else %} <li class="disabled"><span>«</span></li> {% endif %} {% for i in paginator.page_range %} {% if page_obj.number == i %} <li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li> {% else %} <li><a href="?q={{ search_query }}&page={{ i }}">{{ i }}</a></li> {% endif %} {% endfor %} {% if page_obj.has_next %} <li><a href="?q={{ search_query }}&page={{ page_obj.next_page_number }}">»</a></li> {% else %} <li class="disabled"><span>»</span></li> {% endif %} </ul> {% endif %}
额外小优化
你视图里的get_queryset方法有两个重复的return queryset_list,虽然不影响功能,但建议删掉一个,让代码更整洁。
内容的提问来源于stack exchange,提问作者Rashid Aziz
相关产品推荐
相关产品推荐

