zoukankan      html  css  js  c++  java
  • 扩展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美观了一下,效果:

  • 相关阅读:
    MongoDB 组合多个条件查询($and、$in、$gte、$lte)
    KafkaConsumer 长时间地在poll(long )方法中阻塞
    Spring MVC整合Mybatis 入门
    JAVA正确地自定义比较对象---如何重写equals方法和hashCode方法
    MyBatis简单使用和入门理解
    使用二分查找判断某个数在某个区间中--如何判断某个IP地址所属的地区
    FastJson使用示例
    linux(ubuntu) 开发环境配置
    android自定义风格的toast
    iPhone跳转的动画效果类型及实现方法 CATransition
  • 原文地址:https://www.cnblogs.com/zzmx0/p/13469295.html
Copyright © 2011-2022 走看看