Django 3.2版本本月正式发布了, 其中一个重要变化就是新增了智能分页get_elided_page_range方法。Django 3.2之前的Paginator类将连续输出所有页码,非常不智能。本文将演示如何使用get_elided_page_range方法实现智能分页。
get_elided_page_range方法解读
改方法接收3个参数,第一个参数number为当前页码数, on_each_side为当前页码左右两边的页数,on_ends为首尾页码范围。
Paginator.get_elided_page_range(number, on_each_side=3, on_ends=2)
如果当前页码为第10页,使用该方法将输出如下页码范围(page_range)。10左右两边各有3页,首尾各有2页,其余页码号码用...代替。将page_range这个变量传递到前端模板进行遍历即可实现智能分页。
[1, 2, '…', 7, 8, 9, 10, 11, 12, 13, '…', 49, 50]
Django 3.2之前版本非智能分页
我们有个House模型。为了模拟总页数非常多的情形,我们将每页记录数量设为1条。视图函数如下所示:
# Filter houses
def house_filter(request):
qs = House.objects.all()
paginator = Paginator(qs, 1) # 每页1条记录
page = request.GET.get('page', 1) # 获取当前page页码,默认为1
try:
page_obj = paginator.page(page) # 分页
except PageNotAnInteger:
page_obj = paginator.page(1)
except EmptyPage:
page_obj = paginator.page(paginator.num_pages)
is_paginated = True if paginator.num_pages > 1 else False
context = {'page_obj': page_obj, 'paginator': paginator,
'is_paginated': is_paginated,}
return render(request, 'house/house_index.html', context)
假如前端模板样式用bootstrap 4,对应分页的前端模板如下所示:
# house/house_index.html
{% block content %}
描述
小区
城市
房型
朝向
面积
价格(万元)
{% if page_obj %}
{% for item in page_obj %}
{
{ item.description }}
{
{ item.community }}
{
{ item.community.get_city_display }}
{
{ item.get_bedroom_display }}
{
{ item.get_direction_display }}
{
{ item.area }}
{
{ item.price }}
{% endfor %}
{% endif %}
{% if is_paginated %}
{% endif %}
分页效果如下所示,所有页码都展示了,非常的长,显然不是我们想要的。
本例所使用House模型及完整样式代码见Django 3.0实战: 仿链家二手房信息查询网(附GitHub源码)。如果你还不知道如何在Django函数视图和基于类的视图中使用分页,请阅读下篇文章(点击原文阅读即可跳转)。
https://pythondjango.cn/django/basics/14-pagination/
现在我们就要对前面的视图和模板代码做出修改,实现智能分页。
Django 3.2智能分页
首先我们修改视图函数,使用get_elided_page_range方法获取智能分页范围(page_range), 并将这个变量传递给前端模板。
# Filter houses
def house_filter(request):
qs = House.objects.all()
paginator = Paginator(qs, 1) # 每页1条记录
page = request.GET.get('page', 1) # 获取当前page页码,默认为1
try:
page_obj = paginator.page(page) # 分页
except PageNotAnInteger:
page_obj = paginator.page(1)
except EmptyPage:
page_obj = paginator.page(paginator.num_pages)
is_paginated = True if paginator.num_pages > 1 else False
# 注意下面一行, 获取智能页码范围,并传递给模板
page_range = paginator.get_elided_page_range(page, on_each_side=3, on_ends=2)
context = {'page_obj': page_obj, 'paginator': paginator,
'is_paginated': is_paginated, 'page_range': page_range }
return render(request, 'house/house_index.html', context)
模板中我们只需要修改一行代码,如下所示:
{% block content %}
描述
小区
城市
房型
朝向
面积
价格(万元)
{% if page_obj %}
{% for item in page_obj %}
{
{ item.description }}
{
{ item.community }}
{
{ item.community.get_city_display }}
{
{ item.get_bedroom_display }}
{
{ item.get_direction_display }}
{
{ item.area }}
{
{ item.price }}
{% endfor %}
{% endif %}
{% if is_paginated %}
{% if page_obj.has_previous %}
- Previous
{% else %}
- Previous
{% endif %}
# 注意下面一行代码
{% for i in page_range %}
{% if page_obj.number == i %}
- {
{ i }} (current)
# 如果页码为...跳转到第一页
{% elif i == '…' %}
- {
{ i }}
{% else %}
- {
{ i }}
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
- Next
{% else %}
- Next
{% endif %}
{% endif %}
如果你还没注意模板中代码的变化,请再观察一下:
# Django 3.2之前
{% for i in page_obj.paginator.page_range %}
# Django 3.2之后
{% for i in page_range %}
新的展示效果是不是帅多了?
本例仅展示了如何在函数视图中使用智能分页。如果你希望在基于类的视图中也使用智能分页,你可以重写get_context_data方法向模板传递智能页码范围page_range即可。
大江狗
2021.4
相关阅读
Django 3.2正式发布! 主要变化抢先看!
Django 3.0实战: 仿链家二手房信息查询网(附GitHub源码)
Django代码分享: 可以重用的Bootstrap 4分页模板