Django切换分页、排序时搜索筛选参数丢失如何修复?
问题根源
你的分页链接仅携带了page参数,原有筛选参数(location、category、look_for)、排序参数(sort_by)、分页数量参数(paginate_by)都没有被携带到新的URL中,后端接收到请求后没有筛选条件,自然返回全部数据。
修复步骤
第一步:修改视图层,传递保留参数到模板
修改SearchView的get_context_data方法,将除page之外的所有GET请求参数编码后传到模板上下文:
def get_context_data(self, *args, **kwargs): context = super(SearchView, self).get_context_data(*args, **kwargs) # 复制当前GET参数 query_params = self.request.GET.copy() # 移除page参数,避免后续拼接重复 query_params.pop('page', None) # 编码为URL参数字符串传到模板 context['query_params'] = query_params.urlencode() return context
第二步:修改模板分页链接,拼接保留参数
把所有分页的href属性都修改为以下格式,先拼接保留的筛选参数,再加page参数:
{% if is_paginated %} {% if page_obj.has_previous %} <li> <a href="?{% if query_params %}{{ query_params }}&{% endif %}page=1" aria-label="First"> <span aria-hidden="true">First</span> </a> </li> <li> <a href="?{% if query_params %}{{ query_params }}&{% endif %}page={{ page_obj.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% endif %} {% for num in page_obj.paginator.page_range %} {% if page_obj.number == num %} <li class="active"><a href="?{% if query_params %}{{ query_params }}&{% endif %}page={{num}}">{{num}}</a></li> {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3'%} <li><a href="?{% if query_params %}{{ query_params }}&{% endif %}page={{num}}">{{num}}</a></li> {% endif %} {% endfor %} {% if page_obj.has_next %} <li> <a href="?{% if query_params %}{{ query_params }}&{% endif %}page={{ page_obj.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span></a> <li> <a href="?{% if query_params %}{{ query_params }}&{% endif %}page={{ page_obj.paginator.num_pages }}" aria-label="Last"> <span aria-hidden="true">Last</span></a> {% endif %} {%endif%}
这个修改同时解决了切换排序、调整每页数量时的参数丢失问题,因为所有除page外的参数都会被保留。
代码优化建议
- 简化
get_queryset逻辑,无需嵌套多层判断,动态构建查询条件即可:
def get_queryset(self): queryset = super().get_queryset() # 逐个判断参数是否有效,有效就加筛选 location = self.request.GET.get('location', '').strip() category = self.request.GET.get('category', '').strip() look_for = self.request.GET.get('look_for', '').strip() if location: queryset = queryset.filter(city__icontains=location) if category: queryset = queryset.filter(category__slug=category) if look_for: queryset = queryset.filter(property_status=look_for) return queryset
- 优化
get_paginate_by的类型校验,避免传入非数字参数报错:
def get_paginate_by(self, queryset): paginate_by = self.request.GET.get("paginate_by", self.paginate_by) try: return int(paginate_by) except (ValueError, TypeError): return self.paginate_by
- 排序规则可以用字典映射替代多层
if elif,更易维护:
def get_ordering(self): sort_map = { "Name": "-title", "Price": "-price", "Date": "-pub_date" } sort_by = self.request.GET.get('sort_by') return sort_map.get(sort_by, self.ordering)
内容的提问来源于stack exchange,提问作者Farshad Zargari
相关产品推荐
相关产品推荐

