如何为Django搜索结果实现分页功能并优化search视图代码
Django搜索结果分页实现与视图优化方案
分页实现核心逻辑
你已经在index页实现了基础分页,搜索结果的分页逻辑完全通用——Django内置的Paginator支持接收任意QuerySet对象,不管是全量数据还是多条件过滤后的结果,都可以直接传入分页。
先修复现有代码的2个bug
在加分页之前先修正两个过滤逻辑的错误,否则搜索结果本身就不对:
job_type过滤条件错误传入了整个选项元组job_type_choices作为匹配值,应该使用前端传回的job_type参数industry过滤条件同理,错误传入了industry_choices,应该使用前端传回的industry参数
视图层改造步骤
- 确保文件顶部已导入分页类:
from django.core.paginator import Paginator - 所有过滤逻辑执行完成后,追加和index页完全一致的分页代码,把最终分页后的对象传给模板即可。
优化后的完整search视图代码
def search(request): # 初始化查询集,和列表页保持一致:只展示已发布职位,按发布时间倒序 queryset = Job.objects.order_by('-publishing_date').filter(is_published=True) # 一次性提取所有搜索参数,无需手动判断key是否存在 keywords = request.GET.get('keywords') state = request.GET.get('state') job_type = request.GET.get('job_type') industry = request.GET.get('industry') salary = request.GET.get('salary') # 按需追加过滤条件 if keywords: queryset = queryset.filter(description__icontains=keywords) if state: queryset = queryset.filter(location__iexact=state) if job_type: queryset = queryset.filter(job_type__iexact=job_type) if industry: queryset = queryset.filter(industry__icontains=industry) if salary: queryset = queryset.filter(salary__lte=salary) # 执行分页:每页6条,和列表页配置统一 paginator = Paginator(queryset, 6) page_num = request.GET.get('page') paged_jobs = paginator.get_page(page_num) context = { 'location_choices': location_choices, 'salary_choices': salary_choices, 'job_type_choices': job_type_choices, 'industry_choices': industry_choices, 'jobs': paged_jobs, 'values': request.GET, } return render(request, 'jobs/search.html', context)
模板层适配注意点
翻页时必须保留原有搜索参数,否则点击下一页后筛选条件会丢失,直接回到全量职位列表。不需要手动逐个拼接参数,用Django自带的urlencode方法即可自动生成带所有现有GET参数的查询串,分页组件示例:
<div class="pagination-wrapper"> {% if jobs.has_previous %} <a href="?page={{ jobs.previous_page_number }}&{{ request.GET.urlencode }}" class="page-btn">上一页</a> {% endif %} {% for num in jobs.paginator.page_range %} {% if jobs.number == num %} <span class="page-btn active">{{ num }}</span> {% else %} <a href="?page={{ num }}&{{ request.GET.urlencode }}" class="page-btn">{{ num }}</a> {% endif %} {% endfor %} {% if jobs.has_next %} <a href="?page={{ jobs.next_page_number }}&{{ request.GET.urlencode }}" class="page-btn">下一页</a> {% endif %} </div>
视图优化说明
原来的写法可以正常运行,调整后更符合Django的常规写法,可维护性更高:
- 去掉冗余的
if 'xxx' in request.GET判断:request.GET.get('xxx')在key不存在时默认返回None,空字符串、None在if判断中都属于假值,原有判空逻辑完全不受影响,代码量减少近三分之一 - 统一基础过滤规则:原搜索逻辑没有加
is_published=True过滤,会把后台未发布的职位也暴露在搜索结果中,和列表页规则对齐后避免数据泄露 - 参数提取前置:所有搜索参数在过滤逻辑前一次性取出,代码结构更清晰,不会出现取值、过滤逻辑混写的情况
- 分页逻辑和列表页完全对齐:后续如果要调整每页展示数量,只需要把
6抽成全局配置项即可,不需要修改两处代码
额外说明:Django的QuerySet是懒加载的,链式调用filter的时候不会真正执行数据库查询,只有当Paginator取对应页数据、或者模板遍历职位列表时才会生成带LIMIT/OFFSET的分页SQL,不会出现查询全表的性能问题。
内容的提问来源于stack exchange,提问作者QwertyC-137
相关产品推荐
相关产品推荐

