扩展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的分页模块由于django对数据库的惰性查询才可以适用,在别的框架或用途中是不能够使用的,因为它需要先将需要的所有数据从数据库中查询出来,这样肯定是不对的。

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

封装方法有:

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

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

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

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

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

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

下面上代码:

  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="/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="/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="/index2.html?%s">%s</a>' % (self.new_params.urlencode(),i)
 83             else:
 84                 temp = '<li><a href="/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="/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="/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美观了一下,效果:

原文地址:https://www.cnblogs.com/zzmx0/p/13469295.html