天天看点

第20天,分页器

本篇写了使用Django自有的分页器paginator的用法和自定制分页器

1.1 Django之分页功能

Django提供了一个新的类来帮助你管理分页数据,这个类存放在django/core/paginator.py.它可以接收列表、元组或其它可迭代的对象。

1.1.1 基本语法实例

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
 
import os
 
from django.core.paginator import Paginator
objects = ['john','paul','george','ringo','lucy','meiry','checy','wind','flow','rain']<br>
p = Paginator(objects,3)  # 3条数据为一页,实例化分页对象
print(p.count)  # 10 对象总共10个元素
print(p.num_pages)  # 4 对象可分4页
print(p.page_range)  # range(1, 5) 对象页的可迭代范围
 
page1 = p.page(1)  # 取对象的第一分页对象
print(page1.object_list)  # 第一分页对象的元素列表['john', 'paul', 'george']
print(page1.number)  # 第一分页对象的当前页值 1
 
page2 = p.page(2)  # 取对象的第二分页对象
print(page2.object_list)  # 第二分页对象的元素列表 ['ringo', 'lucy', 'meiry']
print(page2.number)  # 第二分页对象的当前页码值 2
 
print(page1.has_previous())  # 第一分页对象是否有前一页 False
print(page1.has_other_pages())  # 第一分页对象是否有其它页 True
 
print(page2.has_previous())  # 第二分页对象是否有前一页 True
print(page2.has_next())  # 第二分页对象是否有下一页 True
print(page2.next_page_number())  # 第二分页对象下一页码的值 3
print(page2.previous_page_number())  # 第二分页对象的上一页码值 1
print(page2.start_index())  # 第二分页对象的元素开始索引 4
print(page2.end_index())  # 第2分页对象的元素结束索引 6
           

1.1.2 在视图中的应用

在项目目录下创建一个名为utils的python包,在utils中创建一个生成页码数字的工具page_numbers.py

def page_numbers(page,total_page,pager_count=11):
    # 传一个页码,对这个页码进行前减后加,产生连续的11个数,加入到列表中,最后将数字列表返回;
    # page: 当前页
    # max_pages : 总页数
    # pager_count: 页面上显示多少个页码,默认是11个

    half_pager_count = pager_count // 2

    if total_page < pager_count:
        page_start = 1
        page_end = total_page
    else:
        if page <= half_pager_count:
            page_start = 1
            page_end = pager_count
        else:
            if (page + half_pager_count) > total_page:
                page_start = total_page - pager_count +1
                page_end = total_page
            else:
                page_start = page - half_pager_count
                page_end = page + half_pager_count

    num_list = [i for i in range(page_start, page_end+1)]
    return num_list
           

视图函数:

# 先导入页码数字生成工具
from utils.page_numbers import page_numbers

def index(req):
    # 获取页码传过来的页码数
    page = req.GET.get('page')
    if not page:     #直接输入ip:port访问时,不带参数,page就为None,这时直接让page=1
        page = 1
    else:
        page = int(page)

    book_list = Book.objects.all()
    p = Paginator(book_list,10)    # 每页显示10条数据

    # 生成页码数字列表
    num_list = page_numbers(page,p.num_pages)   #p.num_pages是从数据库中取出的所有数据每10条数据为一页,总共可以分成多少页

    try:
        book_list = p.page(page)
    except PageNotAnInteger:
        # 如果page的值不是整型,则提供第一页
        book_list = p.page(1)
    except EmptyPage:
        # 如果page的值超过总页数,则提供最后一页
        book_list = p.page(p.num_pages)

    if req.method == "POST":
        title=req.POST.get('title')
        book_list=Book.objects.filter(title__icontains=title)
    return render(req,'index.html',locals())
           

1.1.3 模版文件中使用

注意:分页组件是基于bootstrap写的,需要先引入bootstrap.min.css文件,否则样式加载不成功。

<nav aria-label="Page navigation ">
  <ul class="pagination pagination-lg">

    {#  增加首页,并且判断没有上一页的时候,不显示首页(为空)#}
    {% if book_list.has_previous %}
       <li class="page_num">
            <a href="?page=1">首页</a>
        </li>
    {% endif %}

    {# 判断是否有上一页#}
    {% if book_list.has_previous %}
      <li>
          <a href="?page={{ book_list.previous_page_number }}" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
      </li>
    {% else %}
      <li class="disabled">
          <a href="" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
      </li>
    {% endif %}

    {# 中间的数字页#}
    {% for num in num_list %}
        {% if page == num %}
            <li class="page_num active">
                <a href="?page={{ num }}">{{ num }}</a>
            </li>
        {% else %}
            <li class="page_num">
                <a href="?page={{ num }}">{{ num }}</a>
            </li>
        {% endif %}
    {% endfor %}

{#        判断是否有下一页#}
    {% if book_list.has_next %}
        <li>
          <a href="?page={{ book_list.next_page_number }}" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
    {% else %}
        <li class="disabled">
          <a href="" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
    {% endif %}

{#  增加尾页,并且判断没有下一页的时候,不显示尾页(为空)#}
    {% if book_list.has_next %}
        <li class="page_num">
            <a href="?page={{ p.num_pages }}">尾页</a>
        </li>
    {% endif %}
  </ul>
</nav>
           

1.2 自定制分页组件

命名为pagination.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Page(object):
    def __init__(self,current_page,all_count,base_url,per_page=10,pager_page_count=11):
        """
        分页初始化
        :param current_page: 当前页码
        :param all_count: 数据库中数据的总条数
        :param base_url: 向哪个URL传递页码参数
        :param per_page: 每页显示数据条数
        :param pager_page_count: 页面上最多显示的页码个数
        """
        self.current_page = current_page
        self.all_count = all_count
        self.base_url = base_url
        self.per_page = per_page
        self.pager_page_count = pager_page_count
        pager_count, b = divmod(all_count,per_page)
            #整除,all_count除以per_page,商是pager_count,余数是b
        if b != 0:
            pager_count +=1
        self.pager_count = pager_count    # 总页数

        half_pager_page_count = pager_page_count // 2
        self.half_pager_page_count = half_pager_page_count

    @property
    def start(self):
        """
        数据获取起始索引
        :param self: 
        :return: 
        """
        return (self.current_page -1) * self.per_page

    @property
    def end(self):
        """
        数据获取结束索引
        :return: 
        """
        return self.current_page * self.per_page

    def page_html(self):
        """
        生成HTML页码代码
        :return: 
        """
        # 如果数据产生的总页码数(pager_count) < 页面上显示的页码个数(pager_page_count)默认是11
        if self.pager_count < self.pager_page_count:
            pager_start = 1
            pager_end = self.pager_count
        else:
            # 数据页码已经超过11
            # 判断,如果当前页码 <= 5
            if self.current_page <= self.half_pager_page_count:
                pager_start = 1
                pager_end = self.pager_page_count
            else:
                # 如果: 当前页+5 > 总页码
                if (self.current_page + self.half_pager_page_count) > self.pager_count:
                    pager_start = self.pager_count - self.pager_page_count + 1
                    pager_end = self.pager_count
                else:
                    pager_start = self.current_page - self.half_pager_page_count
                    pager_end = self.current_page + self.half_pager_page_count

        page_list = []

        # 首页
        if self.current_page == 1:
            first_page = ''
        else:
            first_page = '<li><a href="%s?page=1">首页</a><li>'%(self.base_url,)
        page_list.append(first_page)

        # 上一页
        if self.current_page <= 1:
            prev = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev = '<li><a href="%s?page=%s">上一页</a><li>'%(self.base_url,self.current_page-1,)
        page_list.append(prev)

        # 中间页码
        for i in range(pager_start, pager_end+1):
            if self.current_page == i:
                tpl = '<li class="active"><a href="%s?page=%s">%s</a></li>' %(self.base_url,i,i,)
            else:
                tpl = '<li><a href="%s?page=%s">%s</a></li>' % (self.base_url, i, i,)
            page_list.append(tpl)

        # 下一页
        if self.current_page >= self.pager_count:
            nex = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            nex = '<li><a href="%s?page=%s">下一页</a></li>' %(self.base_url,self.current_page+1)
        page_list.append(nex)

        # 尾页
        if self.current_page == self.pager_count:
            last_page = ''
        else:
            last_page = '<li><a href="%s?page=%s">尾页</a></li>' %(self.base_url,self.pager_count)
        page_list.append(last_page)

        page_str = "".join(page_list)   # 生成页码html代码

        return page_str    # 返回的字符串可直接放在模版文件中通过过滤器safe渲染到页面中
           
def index(req):
    from utils.pagination import Page  # 引入自己写的分页工具

    # 当前页
    current_page = req.GET.get('page')
    if current_page:
        current_page = int(current_page)
    else:
        current_page = 1
    # 数据总数
    all_count = Book.objects.all().count()

    # 实例化出分页对象
    # req.path_info是当前页面的URL,也可以自定义,如:"/index.html"
    page_obj = Page(current_page,all_count,req.path_info)

    book_list=Book.objects.all()[page_obj.start:page_obj.end]
    page_str = page_obj.page_html()
    return render(req,'index.html',locals())
           

模版文件中引用:

注意先引入bootstrap.min.css文件

<nav aria-label="Page navigation ">
        <ul class="pagination pagination-lg">
            {{ page_str|safe }}
        </ul>
    </nav>
           

1.3 JS获取当前页面URL中的参数

<script>
        //这段JS代码功能是,点击某一页后,其页码一直保持着重显示
        function UrlSearch() {
           var name,value;
           var str=location.href; //取得整个地址栏
           var num=str.indexOf("?");
           str=str.substr(num+1); //取得所有参数   stringvar.substr(start [, length ]

           var arr=str.split("&"); //各个参数放到数组里
           for(var i=0;i < arr.length;i++){
                num=arr[i].indexOf("=");
                if(num>0){
                     name=arr[i].substring(0,num);
                     value=arr[i].substr(num+1);
                     this[name]=value;
                 }
           }
        }
        var Request=new UrlSearch(); //实例化
        var current_page_num = Request.page;   //获取当前URL中的页码数

        $('.page_num a').each(function () {
            if ($(this).attr('data') == current_page_num){
                $(this).parent().addClass("active");
            }
        });
    </script>