扩展Django中的分页

摘要:
Django封装了分页模块,并定义了两个类,Paginator和Page。虽然它可以满足一般要求,但它太弱了,无法添加一些新功能。此外,在创建分页器类对象时,需要传递所有数据对象,并且没有可移植性。{{posts.next_page}“˃下一页{%else%}下一页面{%endif%}效果:第三,自定义分页组件在开始时表示django的分页模块是由于

Django中封装了分页模块,定义了两个类分别是Paginator和Page。虽然可以满足一般的需求,但是稍想添加点新的功能就显得鸡肋,而且创建paginator类对象时需要传人所有的数据对象(由于django的惰性查询所以适用django),没有可移植性。

下面先在原分类模块基础上另外封装两个功能,分别实现设置页面最多显示页码数 和切换页码时保留原搜索条件。

一、设置页面最多显示页码数

设置最多页码数后,页面显示的页码和总页码数还有当前页码有关,封装一个类继承自Paginator,定义pager_num_range方法如下:

 1 from django.core.paginator import Paginator
 2 
 3 class CustomPaginator(Paginator):
 4 
 5     def __init__(self,current_page,per_pager_number,*args, **kwargs):
 6         # 当前页
 7         self.current_page = int(current_page)
 8         # 页面最多显示的页码数
 9         self.per_pager_number = int(per_pager_number)
10         self.per_pager_number = int(per_pager_number)
11         super(CustomPaginator,self).__init__(*args, **kwargs)
12 
13     def pager_num_range(self):
14         # 页码最多显示的页码数的一半
15         part = self.per_pager_number // 2
16         # 总页数小于最多显示的页码数
17         if self.num_pages < self.per_pager_number:
18             return range(1, self.num_pages+1)
19         # 当前页小于最多显示页码数的一半
20         elif self.current_page <= part:
21             return range(1, self.per_pager_number+1)
22         # 当前页在最后的几页(从最多显示页码的一半往后几页)
23         elif self.num_pages - self.current_page <= part:
24             return range(self.num_pages-self.per_pager_number+1,self.num_pages+1)
25         # 其余情况
26         else:
27             if self.per_pager_number % 2 == 0:
28                 return range(self.current_page-part+1, self.current_page+part+1)
29             else:
30                 return range(self.current_page-part, self.current_page+part+1)

然后创建paginator类对象是通过CustomPaginator类创建即可,传入必要的参数

paginator = CustomPaginator(current_page,11,USER_LIST,10)

最后创建page类对象,渲染模板即可,模板中page类对象调用paginator.pager_numrange方法即可获取设置最多显示页码数后的页码列表,简单配置一下

{% for i in posts.paginator.pager_num_range %}
    {% if i == posts.number %}
        <a style="font-size: 30px">{{ i }}</a>
    {% else %}
        <a href="/index1.html?p={{ i }}">{{ i }}</a>
    {% endif %}
{% endfor %}

二、切换页码时保留搜索条件

切换页码保留搜索条件,需要先获取请求url中的所有参数,然后在操作上一页、下一页、点击页码时只需修改url参数中对应的页码,将修改后的url参数设置给page类对象的属性 传给前端即可。

 1 from django.core.paginator import Paginator
 2 
 3 def index3(request):
 4     paginator = Paginator(USER_LIST, 10)
 5     data = request.GET
 6     current_page = data.get('p')
 7     posts = paginator.page(current_page)
 8 
 9     """修改页码支持保留搜索条件"""
10     import copy
11     data = copy.deepcopy(data)
12 
13     # 总页数
14     all_num, b = divmod(len(USER_LIST), 10)
15     if b != 0:
16         all_num += 1
17 
18     # 传入的页码值有误
19     try:
20         current_page = int(current_page)
21     except Exception as e:
22         current_page = 1
23 
24     # 传入的页码值大于总页数
25     if current_page >= all_num:
26         current_page = all_num
27 
28     # 上一页
29     data['p'] = current_page - 1
30     posts.previous_page = "%s" % data.urlencode()
31 
32     # 下一页
33     data['p'] = current_page + 1
34     posts.next_page = "%s" % data.urlencode()
35 
36     # 页面显示的页码
37     # 每一页需要分别保存url参数和页码值
38     posts.num_li = []
39     for i in range(1,all_num+1):
40         data['p'] = i
41         #                      url参数                页码值
42         posts.num_li.append({"data":data.urlencode(),"p":i})
43 
44     return render(request, 'index3.html',{"posts":posts})

然后在模板中分别通过page对象的对应属性 获取对应的url参数拼接到url中即可

    {% if posts.has_previous %}
    <a href="/index3.html?{{ posts.previous_page }}">上一页</a>
    {% else %}
    <a>上一页</a>
    {% endif %}

    {% for i in posts.num_li %}
        {% if i.p == posts.number %}
            <a style="font-size: 30px" href="/index3.html?{{ i.data }}">{{ i.p }}</a>
        {% else %}
            <a href="/index3.html?{{ i.data }}">{{ i.p }}</a>
        {% endif %}
    {% endfor %}

    {% if posts.has_next %}
        <a href="/index3.html?{{ posts.next_page }}">下一页</a>
    {% else %}
    <a>下一页</a>
    {% endif %}

效果:

扩展Django中的分页第1张

三、自定义分页组件

最开始说过了,django的分页模块由于django对数据库的惰性查询才可以适用,在别的框架或用途中是不能够使用的,因为它需要先将需要的所有数据从数据库中查询出来,这样肯定是不对的。

自己封装一个Paginator类,传入四个参数:所有数据的个数、当前页码值、每页显示多少条 和 页面显示的最多页码数。

封装方法有:

  start()、end():第几页的数据 起始切片和结束切片

  num_pages():总页数,用property属性将其设置属性

  pager_num_range():获取页面显示的页码

  pager_str():页面所有与页码相关的按钮html代码

思路:起始切片和结束切片没什么好说的了,总页数通过python的内置函数divmod()可以得到,页面显示的页码上面写过了,和页码相关的按钮html代码这个的用意是 模板中只需要写上创建的paginator对象.pager_str,那么和页码相关的就都完事了。

     做法就是 和 切换页面保留搜索条件一样 拼接url参数。我这里直接写死了url前面部分,可以通过给方法添加一个参数来改变url前面部分,这样更通用点。

下面上代码:

扩展Django中的分页第2张扩展Django中的分页第3张
  1 class Paginator(object):
  2 
  3     def __init__(self, totalCount,currentPage,request,perPageItemNum=10,maxPageNum=7):
  4         """
  5         初始化
  6         :param totalCount: 所有数据的个数
  7         :param currentPage: 当前页
  8         :param perPageItemNum:每页显示多少条
  9         :param maxPageNum:页面显示的最多页码数
 10         """
 11         self.total_count = totalCount
 12         try:
 13             v = int(currentPage)
 14             if v <= 0:
 15                 v = 1
 16             self.current_page = v
 17         except Exception as e:
 18             self.current_page = 1
 19         self.per_page_item_num = perPageItemNum
 20         self.max_page_num = maxPageNum
 21 
 22         # 获取url中的筛选条件:<QueryDict:{key: value}>
 23         params = request.GET
 24         import copy
 25         self.new_params = copy.deepcopy(params)
 26 
 27     def start(self):
 28         # 起始切片
 29         return (self.current_page-1)*self.per_page_item_num
 30 
 31     def end(self):
 32         # 结束切片
 33         return self.current_page*self.per_page_item_num
 34 
 35     @property
 36     def num_pages(self):
 37         """总页数"""
 38         a, b = divmod(self.total_count, self.per_page_item_num)
 39         if b != 0:
 40             a += 1
 41         return a
 42 
 43     def pager_num_range(self):
 44         # 页码最多显示的页码数的一半
 45         part = self.max_page_num // 2
 46         # 总页数小于最多显示的页码数
 47         if self.num_pages < self.max_page_num:
 48             return range(1, self.num_pages+1)
 49         # 当前页小于最多显示页码数的一半
 50         elif self.current_page <= part:
 51             return range(1, self.max_page_num+1)
 52         # 当前页在最后的几页(从最多显示页码的一半往后几页)
 53         elif self.num_pages - self.current_page <= part:
 54             return range(self.num_pages-self.max_page_num+1,self.num_pages+1)
 55         # 其余情况
 56         else:
 57             if self.max_page_num % 2 == 0:
 58                 return range(self.current_page-part+1, self.current_page+part+1)
 59             else:
 60                 return range(self.current_page-part, self.current_page+part+1)
 61 
 62     def page_str(self):
 63         page_list = []
 64 
 65         # 首页
 66         self.new_params['p'] = 1
 67         first = '<li><a href="http://t.zoukankan.com/index2.html?%s">首页</a></li>' % self.new_params.urlencode()
 68         page_list.append(first)
 69 
 70         # 上一页
 71         if self.current_page == 1:
 72             prev = '<li><a>上一页</a><>/li'
 73         else:
 74             self.new_params['p'] = self.current_page-1
 75             prev = '<li><a href="http://t.zoukankan.com/index2.html?%s">上一页</a></li>' % (self.new_params.urlencode())
 76         page_list.append(prev)
 77 
 78         # 页面页码
 79         for i in self.pager_num_range():
 80             self.new_params['p'] = i
 81             if self.current_page == i:
 82                 temp = '<li class="active"><a href="http://t.zoukankan.com/index2.html?%s">%s</a>' % (self.new_params.urlencode(),i)
 83             else:
 84                 temp = '<li><a href="http://t.zoukankan.com/index2.html?%s">%s</a></li>' % (self.new_params.urlencode(), i)
 85             page_list.append(temp)
 86 
 87         # 下一页
 88         if self.current_page >= self.num_pages:
 89             next = '<li><a>下一页</a></li>'
 90         else:
 91             self.new_params['p'] = self.current_page+1
 92             next = '<li><a href="http://t.zoukankan.com/index2.html?%s">下一页</a></li>' % (self.new_params.urlencode())
 93         page_list.append(next)
 94 
 95         # 尾页
 96         self.new_params['p'] = self.num_pages
 97         last = '<li><a href="http://t.zoukankan.com/index2.html?%s">尾页</a></li>' % self.new_params.urlencode()
 98         page_list.append(last)
 99 
100         return ' '.join(page_list)
自己封装Paginator

然后视图中创建paginator类对象,渲染模板即可。模板中 禁止转义

def index2(request):
    from app01.pager import Paginator
    current_page = request.GET.get('p')

    obj = Paginator(666,current_page,request)

    data_list = USER_LIST[obj.start():obj.end()]

    return render(request, 'index2.html',{"data_list":data_list,"page_obj":obj})
{{ page_obj.page_str | safe }}

最后用bootstarp美观了一下,效果:

扩展Django中的分页第4张

免责声明:文章转载自《扩展Django中的分页》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇实践Kong for Kubernetes(K8S),kong最新2.1版本和kong-ingress-controller:0.9.1版本C#中实现web端展示JT文件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

vue后台(一)

一,项目准备工作 1.拿到已经是二次开发的代码, npm i , 安装依赖包 ES6模块暴露和导入复习 1. 导出方式一: 默认一次性导出 (只能有一个) export default xxx 本质: 整个模块是一个对象, 对象中有default属性, 即: {default: xxx} 2....

详解S7源码3-COTP and TPKT

连接 S7COMM简介 https://www.anquanke.com/post/id/186099 OSI layer    Protocol Application Layer    S7 communication Presentation Layer    S7 communication(COTP) Session Layer    S7 co...

基于颜色和圆对乒乓球识别_20170329

更新:调整算法,识别出一副图像中最近的球。球越近,图像显示的半径越大,所以只要找出图像中半径最大的球就是最近的球。底盘程序优先处理最近的球。 效果:可以准确的找出一副图像中最近的球。 TIP:  flag1:检测到图像中有球的标志位,1有0无。          flag2:检测到图像中球的个数。 代码如下: HoughCircles(canny_o...

c++STL之heap(堆)

1、误区! 1、堆排序排完后的堆和大顶堆、小顶堆不是一个概念!2、堆分为大顶堆和小顶堆,即要么大顶堆(大根堆/最大堆),要么小顶堆。3、对于堆,堆的根节点一定是堆中所有节点的最大值或者最小值。4、大顶堆只是说这个堆总每一个节点满足:每一个节点大于或者等于其左右娃。并非这个堆一定是从大到小的序列。5、所以才必须要有堆排序呀!堆排序排完了之后的,才一定是一个有...

django 后台格式化数据库查询出的日期

在项目中,我遇到这样的情况,使用ajax获取查询出来的数据,而这些数据中某个字段是日期datetime格式,在模板中显示的样式很怪异。由于前端使用了js控件,也不能使用django的模板过滤器。 所以这种情况下,我想将日期从数据库中查询出来就使用固定好的格式。 django 中直接执行sql语句查询 from django.db import connec...

ORM之单表操作

ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动 ORM是“对象-关系-映射”的简称。 一、单表操作 创建表 1、创建模型 创建名为book的app,在...