Django中的分页器

1 Django的分页器(paginator)简介

在页面显示分页数据,需要用到Django分页器组件

from django.core.paginator import Paginator

paginator对象下的属性及其代表的意义,
使用Paginator(QuerySet对象, 10)生成paginator对象的时候, 第二个参数表示一页显示的数据个数

Paginator对象: paginator = Paginator(QuerySet对象, 10)

# per_page: 每页显示条目数量

# count: 数据总个数

# num_pages:总页数

# page_range:总页数的索引范围,如: (1,10),(1,200)

# page: page对象

paga对象: page对象得到的具体到哪一页的对象, 改对象下的参数如下:

paginator和page两个对象可以看成是一本书, paginator对象是整本书而page是该书的具体的哪一页

page对象:page=paginator.page(1)

# has_next 是否有下一页

# next_page_number 下一页页码

# has_previous 是否有上一页

# previous_page_number 上一页页码

# object_list 分页之后的数据列表

# number 当前页

# paginator paginator对象

在Django中批量向数据库中插入数据的方式:

使用的主要方法: models.UserInfo.objects.bulk_create(objs,batch_size)

def pagetest(request):

# 批量插入数据

# objes:对象列表,batch_size 一次插入数据的量

ll=[]

for i in range(100):

# models.UserInfo.objects.create()

ll.append(models.UserInfo(name='lqz%s'%i,age=i+1))

ret=models.UserInfo.objects.bulk_create(ll,20)



return HttpResponse('ok')

2 应用View层

from django.shortcuts import render,HttpResponse



# Create your views here.

from app01.models import *

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger



def index(request):



'''

批量导入数据:



Booklist=[]

for i in range(100):

Booklist.append(Book(title="book"+str(i),price=30+i*i))

Book.objects.bulk_create(Booklist)

'''

'''

分页器的使用:



book_list=Book.objects.all()



paginator = Paginator(book_list, 10)



print("count:",paginator.count) #数据总数

print("num_pages",paginator.num_pages) #总页数

print("page_range",paginator.page_range) #页码的列表







page1=paginator.page(1) #第1页的page对象

for i in page1: #遍历第1页的所有数据对象

print(i)



print(page1.object_list) #第1页的所有数据





page2=paginator.page(2)



print(page2.has_next()) #是否有下一页

print(page2.next_page_number()) #下一页的页码

print(page2.has_previous()) #是否有上一页

print(page2.previous_page_number()) #上一页的页码







# 抛错

#page=paginator.page(12) # error:EmptyPage



#page=paginator.page("z") # error:PageNotAnInteger



'''





book_list=Book.objects.all()



paginator = Paginator(book_list, 10)

page = request.GET.get('page',1)

currentPage=int(page)





try:

print(page)

book_list = paginator.page(page)

except PageNotAnInteger:

book_list = paginator.page(1)

except EmptyPage:

book_list = paginator.page(paginator.num_pages)





return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})

3 模版层 index.html

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Title</title>

<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"

integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

</head>

<body>



<div class="container">



<h4>分页器</h4>

<ul>



{% for book in book_list %}

<li>{{ book.title }} -----{{ book.price }}</li>

{% endfor %}



</ul>





<ul class="pagination" id="pager">



{% if book_list.has_previous %}

<li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>

{% else %}

<li class="previous disabled"><a href="#">上一页</a></li>

{% endif %}





{% for num in paginator.page_range %}



{% if num == currentPage %}

<li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>

{% else %}

<li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>



{% endif %}

{% endfor %}







{% if book_list.has_next %}

<li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>

{% else %}

<li class="next disabled"><a href="#">下一页</a></li>

{% endif %}



</ul>

</div>







</body>

</html>

4 扩展

当我们的页数比较少的时候,我们可以将所有的页数全部展现到屏幕上供用户选择, 但是当我们的页数过多的时候,就必须要考虑在页面中显示多少个页数合适, 然后其他的页数暂时隐藏起来,需要的时候再显示出来, 具体要求显示多少个根据需求来设定

核心逻辑

'''

显示左5,右5,总共11个页,

1 如果总页码大于11

1.1 if 当前页码减5小于1,要生成1到12的列表(顾头不顾尾,共11个页码)

page_range=range(1,12)

1.2 elif 当前页码+5大于总页码,生成当前页码减10,到当前页码加1的列表(顾头不顾尾,共11个页码)

page_range=range(paginator.num_pages-10,paginator.num_pages+1)

1.3 else 生成当前页码-5,到当前页码+6的列表

page_range=range(current_page_num-5,current_page_num+6)

2 其它情况,生成的列表就是pageinator的page_range

page_range=paginator.page_range



'''
逻辑代码实现:


def index(request):



book_list=Book.objects.all()

paginator = Paginator(book_list, 15)

# 从前端获取当前页

page = request.GET.get('page',1)

currentPage=int(page)



# 如果页数十分多时,换另外一种显示方式

# 我们下边实现的是左5右5的显示方式

# 注意range的取值是顾头不顾尾的



if paginator.num_pages>11:



if currentPage-5<1:

pageRange=range(1,11)

elif currentPage+5>paginator.num_pages:

pageRange=range(currentPage-5,paginator.num_pages+1)



else:

pageRange=range(currentPage-5,currentPage+5)



else:

pageRange=paginator.page_range





try:

print(page)

book_list = paginator.page(page)

except PageNotAnInteger:

book_list = paginator.page(1)

except EmptyPage:

book_list = paginator.page(paginator.num_pages)





return render(request,"index.html",locals())

在views中的使用:
​​​页面较多的时候分页器在views中的使用

def page_test(request):

# book_list=[]

# for i in range(100):

# book=Book(name='book%s'%i,price=10+i,pub_date='2018-09-18',publish_id=1)

# book_list.append(book)

# Book.objects.bulk_create(book_list,10)

book_list=Book.objects.all()

# 生成paginator对象,传入书籍列表,每页10条数据

paginator=Paginator(book_list,3)

# 总页码数

print(paginator.num_pages)

# 页码列表

print(paginator.page_range)

# 总数据

print(paginator.count)

# 获取页面传来的页码

current_page=int(request.GET.get('page',1))

page_range=[]

# 左5 右5



# 获取页面传来的页码的page对象

try:

page=paginator.page(current_page)

# print(page.has_next()) #是否有下一页

# print(page.next_page_number()) #下一页的页码

# print(page.has_previous()) #是否有上一页

# print(page.previous_page_number()) #上一页的页码

# 循环打印出当页对象

for i in page:

print(i)

except Exception as e:

current_page=1

page = paginator.page(1)

if paginator.num_pages>11:

if current_page+5>paginator.num_pages:

page_range=range(paginator.num_pages-10,paginator.num_pages+1)

elif current_page-5<1:

page_range=range(1,12)

else:

page_range=range(current_page-5,current_page+6)

else:

page_range=paginator.page_range







return render(request,'page_test.html',locals())



views

页面较多时分页器在模板中的使用:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">

<title>Title</title>

</head>

<body>



<ul>



{% for foo in page %}

<li>{{ foo.name }}</li>



{% endfor %}



</ul>

<nav aria-label="Page navigation">

<ul class="pagination">

{% if page.has_previous %}

<li>

<a href="/page_test/?page={{ page.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 foo in page_range %}

{% if current_page == foo %}

<li class="active"><a href="/page_test/?page={{ foo }}">{{ foo }}</a></li>

{% else %}

<li><a href="/page_test/?page={{ foo }}">{{ foo }}</a></li>

{% endif %}



{% endfor %}

{% if page.has_next %}

<li>

<a href="/page_test/?page={{ page.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 %}



</ul>

</nav>





</body>

</html>



模版

 2、第三方使用版

class Pagination(object):
    """自定义分页(Bootstrap版)"""
    def __init__(self, current_page, total_count, base_url, per_page=10, max_show=11):
        """
        :param current_page: 当前请求的页码
        :param total_count: 总数据量
        :param base_url: 请求的URL
        :param per_page: 每页显示的数据量,默认值为10
        :param max_show: 页面上最多显示多少个页码,默认值为11
        """
        try:
            self.current_page = int(current_page)
        except Exception as e:
            # 取不到或者页码数不是数字都默认展示第1页
            self.current_page = 1
        # 定义每页显示多少条数据
        self.per_page = per_page
        # 计算出总页码数
        total_page, more = divmod(total_count, per_page)
        if more:
            total_page += 1
        self.total_page = total_page
        # 定义页面上最多显示多少页码(为了左右对称,一般设为奇数)
        self.max_show = max_show
        self.half_show = max_show // 2
        self.base_url = base_url

    @property
    def start(self):
        return (self.current_page-1) * self.per_page

    @property
    def end(self):
        return self.current_page * self.per_page

    def page_html(self):
        # 计算一下页面显示的页码范围
        if self.total_page <= self.max_show:  # 总页码数小于最大显示页码数
            page_start = 1
            page_end = self.total_page
        elif self.current_page + self.half_show >= self.total_page:  # 右边越界
            page_end = self.total_page
            page_start = self.total_page - self.max_show
        elif self.current_page - self.half_show <= 1:  # 左边越界
            page_start = 1
            page_end = self.max_show
        else:  # 正常页码区间
            page_start = self.current_page - self.half_show
            page_end = self.current_page + self.half_show
        # 生成页面上显示的页码
        page_html_list = []
        page_html_list.append('<nav aria-label="Page navigation"><ul class="pagination">')
        # 加首页
        first_li = '<li><a href="{}?page=1">首页</a></li>'.format(self.base_url)
        page_html_list.append(first_li)
        # 加上一页
        if self.current_page == 1:
            prev_li = '<li><a href="#"><span aria-hidden="true">«</span></a></li>'
        else:
            prev_li = '<li><a href="{}?page={}"><span aria-hidden="true">«</span></a></li>'.format(
                self.base_url, self.current_page - 1)
        page_html_list.append(prev_li)
        for i in range(page_start, page_end + 1):
            if i == self.current_page:
                li_tag = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
            else:
                li_tag = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
            page_html_list.append(li_tag)
        # 加下一页
        if self.current_page == self.total_page:
            next_li = '<li><a href="#"><span aria-hidden="true">»</span></a></li>'
        else:
            next_li = '<li><a href="{}?page={}"><span aria-hidden="true">»</span></a></li>'.format(
                self.base_url, self.current_page + 1)
        page_html_list.append(next_li)
        # 加尾页
        page_end_li = '<li><a href="{}?page={}">尾页</a></li>'.format(self.base_url, self.total_page)
        page_html_list.append(page_end_li)
        page_html_list.append('</ul></nav>')
        return "".join(page_html_list)
封装保存版

view中
def publisher_list(request):
    # 从URL中取当前访问的页码数
    current_page = int(request.GET.get('page'))
    # 比len(models.Publisher.objects.all())更高效
    total_count = models.Publisher.objects.count()
    page_obj = Pagination(current_page, total_count, request.path_info)
    data = models.Publisher.objects.all()[page_obj.start:page_obj.end]
    page_html = page_obj.page_html()
    return render(request, "publisher_list.html", {"publisher_list": data, "page_html": page_html})

封装保存版使用示例

自定义分页器的拷贝及使用

"""
当我们需要使用到非django内置的第三方功能或者组件代码的时候
我们一般情况下会创建一个名为utils文件夹 在该文件夹内对模块进行功能性划分
    utils可以在每个应用下创建 具体结合实际情况

我们到了后期封装代码的时候 不再局限于函数
还是尽量朝面向对象去封装

我们自定义的分页器是基于bootstrap样式来的 所以你需要提前导入bootstrap
    bootstrap 版本 v3
    jQuery        版本 v3
"""
# 后端
book_queryset = models.Book.objects.all()
current_page = request.GET.get('page',1)
all_count = book_queryset.count()
# 1 传值生成对象
page_obj = Pagination(current_page=current_page,all_count=all_count)
# 2 直接对总数据进行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end]
# 3 将page_queryset传递到页面 替换之前的book_queryset


# 前端
{% for book_obj in page_queryset %}
    <p>{{ book_obj.title }}</p>
    <nav aria-label="Page navigation">
</nav>
{% endfor %}
{#利用自定义分页器直接显示分页器样式#}
{{ page_obj.page_html|safe }}