本篇写了使用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">«</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="" aria-label="Previous">
<span aria-hidden="true">«</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">»</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="" aria-label="Next">
<span aria-hidden="true">»</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>