分页

一、Django内置分页

#Django 2.0下新增了get_page()方法,可以将代码大大简化(如下图所示)。它所实现的功能与上面是一样的。当用户提交的页码不是整数时,提取第一页记录。当用户输入的页码太大时,只提取最后一页记录。

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Article
from django.shortcuts import render

def article_list(request):
    article_list = Article.objects.all()
    paginator = Paginator(article_list, 10)  # 实例化一个分页对象, 每页显示10个

    page = request.GET.get('page')  # 从URL通过get页码,如?page=3
    articles = paginator.get_page(page)  # 获取某页对应的记录
    
    return render(request, 'article_list.html', {'articles': articles})
Django 2.0下新增了get_page()方法
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

L = []
for i in range(999):
    L.append(i)

def index(request):
    current_page = request.GET.get('p')

    paginator = Paginator(L, 10)
    # per_page: 每页显示条目数量
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    try:
        posts = paginator.page(current_page)
        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表
        # number                当前页
        # paginator             paginator对象
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)
    return render(request, 'index.html', {'posts': posts})
views.py
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul>
    {% for item in posts %}
        <li>{{ item }}</li>
    {% endfor %}
</ul>

<div class="pagination">
      <span class="step-links">
        {% if posts.has_previous %}
            <a href="?p={{ posts.previous_page_number }}">Previous</a>
        {% endif %}
          <span class="current">
            Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
          </span>
          {% if posts.has_next %}
              <a href="?p={{ posts.next_page_number }}">Next</a>
          {% endif %}
      </span>

</div>
</body>
</html>
Html
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger


class CustomPaginator(Paginator):
    def __init__(self, current_page, max_pager_num, *args, **kwargs):
        """
        :param current_page: 当前页
        :param max_pager_num:最多显示的页码个数
        :param args:
        :param kwargs:
        :return:
        """
        self.current_page = int(current_page)
        self.max_pager_num = max_pager_num
        super(CustomPaginator, self).__init__(*args, **kwargs)

    def page_num_range(self):
        # 当前页面
        # self.current_page
        # 总页数
        # self.num_pages
        # 最多显示的页码个数
        # self.max_pager_num
        print(1)
        if self.num_pages < self.max_pager_num:
            return range(1, self.num_pages + 1)
        print(2)
        part = int(self.max_pager_num / 2)
        if self.current_page - part < 1:
            return range(1, self.max_pager_num + 1)
        print(3)
        if self.current_page + part > self.num_pages:
            return range(self.num_pages + 1 - self.max_pager_num, self.num_pages + 1)
        print(4)
        return range(self.current_page - part, self.current_page + part + 1)


L = []
for i in range(999):
    L.append(i)

def index(request):
    current_page = request.GET.get('p')
    paginator = CustomPaginator(current_page, 11, L, 10)
    # per_page: 每页显示条目数量
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    try:
        posts = paginator.page(current_page)
        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表
        # number                当前页
        # paginator             paginator对象
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)

    return render(request, 'index.html', {'posts': posts})
扩展内置分页:views.py
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<ul>
    {% for item in posts %}
        <li>{{ item }}</li>
    {% endfor %}
</ul>

<div class="pagination">
<span class="step-links">
{% if posts.has_previous %}
    <a href="?p={{ posts.previous_page_number }}">Previous</a>
{% endif %}

    {% for i in posts.paginator.page_num_range %}
        <a href="?p={{ i }}">{{ i }}</a>
    {% endfor %}

    {% if posts.has_next %}
        <a href="?p={{ posts.next_page_number }}">Next</a>
    {% endif %}
</span>

<span class="current">
Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
</span>

</div>
</body>
</html>
扩展内置分页:Html

二、自定义分页

"""
分页组件使用示例:

    obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info)
    page_user_list = USER_LIST[obj.start:obj.end]
    page_html = obj.page_html()

    return render(request,'index.html',{'users':page_user_list,'page_html':page_html})


"""


class Pagination(object):

    def __init__(self,current_page,all_count,base_url,per_page_num=2,pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param base_url: 分页中显示的URL前缀
        :param pager_count:  最多显示的页码个数
        """

        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page <1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        self.base_url = base_url

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager


        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

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

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

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []

        first_page = '<li><a href="%s?page=%s">首页</a></li>' % (self.base_url,1,)
        page_html_list.append(first_page)

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

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,)
            else:
                temp = '<li><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,)
            page_html_list.append(temp)

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

        last_page = '<li><a href="%s?page=%s">尾页</a></li>' % (self.base_url,self.all_pager,)
        page_html_list.append(last_page)

        return ''.join(page_html_list)
自定义分页器

自定义分页示例(包含保存搜索条件功能):

"""
分页组件使用示例:

    obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info)
    page_user_list = USER_LIST[obj.start:obj.end]
    page_html = obj.page_html()

    return render(request,'index.html',{'users':page_user_list,'page_html':page_html})

"""

class Pagination(object):

    def __init__(self,current_page_num,all_count,request,per_page_num=2,pager_count=11):
        """
        封装分页相关数据
        :param current_page_num: 当前访问页的数字
        :param all_count:    分页数据中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        """
        try:
            current_page_num = int(current_page_num)
        except Exception as e:
            current_page_num = 1

        if current_page_num <1:
            current_page_num = 1

        self.current_page_num = current_page_num

        self.all_count = all_count
        self.per_page_num = per_page_num

        # 实际总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager


        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)  # 5


        # 保存搜索条件

        import copy
        self.params=copy.deepcopy(request.GET) # {"a":"1","b":"2"}

    @property
    def start(self):
        return (self.current_page_num - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page_num * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page_num <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1
            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page_num + self.pager_count_half) > self.all_pager:

                    pager_start = self.all_pager - self.pager_count + 1
                    pager_end = self.all_pager + 1

                else:
                    pager_start = self.current_page_num - self.pager_count_half
                    pager_end = self.current_page_num + self.pager_count_half + 1

        page_html_list = []

        first_page = '<li><a href="?page=%s">首页</a></li>' % (1,)
        page_html_list.append(first_page)

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

        page_html_list.append(prev_page)


        #self.params=copy.deepcopy(request.GET) # {"a":"1","b":"2"}

        for i in range(pager_start, pager_end):

            self.params["page"]=i

            if i == self.current_page_num:
                temp = '<li class="active"><a href="?%s">%s</a></li>' %(self.params.urlencode(),i)
            else:
                temp = '<li><a href="?%s">%s</a></li>' % (self.params.urlencode(),i,)
            page_html_list.append(temp)


        if self.current_page_num >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page_num + 1,)
        page_html_list.append(next_page)
        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)

        return ''.join(page_html_list)
app01/page.py(包含保存搜索条件功能)
from django.shortcuts import render
from app01.models import Book
from django.core.paginator import Paginator,EmptyPage
from app01.page import Pagination
def index(request):

    '''
    批量插入数据:
        # for i in range(100):
        #     Book.objects.create(title="book_%s"%i,price=i*i)
        book_list=[]

        for i in range(100):
            book=Book(title="book_%s"%i,price=i*i)
            book_list.append(book)

        Book.objects.bulk_create(book_list)

    '''
    # 自定义分页
    
    current_page_num = request.GET.get("page")
    book_list = Book.objects.all()
 pagination=Pagination(current_page_num,book_list.count(),request)
    '''
    count=100
    per_page=9
    
    current_page_num=1       start 0     end 8
    current_page_num=2       start 8     end 16
    current_page_num=3       start 16    end 24 
    current_page_num=n       start (n-1)*per_page    end n*per_page
    
    '''
    book_list = book_list[pagination.start:pagination.end]

    return render(request,"index.html",locals())
views.py
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<ul>
    {% for book in book_list %}
    <li>{{ book.title }} ---- {{ book.price }}</li>
    {% endfor %}
</ul>

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


</body>
</html>
index.html
QueryDict
            # request.GET["xxx"]=123
            print(type(request.GET))
            from django.http.request import QueryDict
            print(request.GET)
            import copy
            params=copy.deepcopy(request.GET)
            params["xxx"]=123
            print("params", params)
            print(params.urlencode()) # "a=1&b=2&xxx=123"
保存搜索条件相关知识

 

分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。

1、设定每页显示数据条数

2、用户输入页码(第一页、第二页...)

3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

4、在数据表中根据起始位置取值,页面上输出数据


需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]

1、设定每页显示数据条数

2、用户输入页码(第一页、第二页...)

3、设定显示多少页号

4、获取当前数据总条数

5、根据设定显示多少页号和数据总条数计算出,总页数

6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

7、在数据表中根据起始位置取值,页面上输出数据

8、输出分页html,如:[上一页][1][2][3][4][5][下一页]

#!/usr/bin/env python
# _*_coding:utf-8_*_
from django.utils.safestring import mark_safe
 
class PageInfo(object):
    def __init__(self,current,totalItem,peritems=5):
        self.__current=current
        self.__peritems=peritems
        self.__totalItem=totalItem
    def From(self):
        return (self.__current-1)*self.__peritems
    def To(self):
        return self.__current*self.__peritems
    def TotalPage(self):  #总页数
        result=divmod(self.__totalItem,self.__peritems)
        if result[1]==0:
            return result[0]
        else:
            return result[0]+1
 
def Custompager(baseurl,currentPage,totalpage):  #基础页,当前页,总页数
    perPager=11
    #总页数<11
    #0 -- totalpage
    #总页数>11
        #当前页大于5 currentPage-5 -- currentPage+5
            #currentPage+5是否超过总页数,超过总页数,end就是总页数
        #当前页小于5 0 -- 11
    begin=0
    end=0
    if totalpage <= 11:
        begin=0
        end=totalpage
    else:
        if currentPage>5:
            begin=currentPage-5
            end=currentPage+5
            if end > totalpage:
                end=totalpage
        else:
            begin=0
            end=11
    pager_list=[]
    if currentPage<=1:
        first="<a href=''>首页</a>"
    else:
        first="<a href='%s%d'>首页</a>" % (baseurl,1)
    pager_list.append(first)
 
    if currentPage<=1:
        prev="<a href=''>上一页</a>"
    else:
        prev="<a href='%s%d'>上一页</a>" % (baseurl,currentPage-1)
    pager_list.append(prev)
 
    for i in range(begin+1,end+1):
        if i == currentPage:
            temp="<a href='%s%d' class='selected'>%d</a>" % (baseurl,i,i)
        else:
            temp="<a href='%s%d'>%d</a>" % (baseurl,i,i)
        pager_list.append(temp)
    if currentPage>=totalpage:
        next="<a href='#'>下一页</a>"
    else:
        next="<a href='%s%d'>下一页</a>" % (baseurl,currentPage+1)
    pager_list.append(next)
    if currentPage>=totalpage:
        last="<a href=''>末页</a>"
    else:
        last="<a href='%s%d'>末页</a>" % (baseurl,totalpage)
    pager_list.append(last)
    result=''.join(pager_list)
    return mark_safe(result)   #把字符串转成html语言
分页实例
views.py

from django.shortcuts import render,HttpResponse
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:
        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})






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>





views.py( 如果页数十分多时,换另外一种显示方式)

def index(request):
    book_list=Book.objects.all()

    paginator = Paginator(book_list, 15)
    #page = request.GET.get('page',1)
    page = request.GET.get('page')
    currentPage=int(page)

    #  如果页数十分多时,换另外一种显示方式
    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:
    #    book_list = paginator.page(page)
    #except PageNotAnInteger:
    #    book_list = paginator.page(1)
    #except EmptyPage:
    #    book_list = paginator.page(paginator.num_pages)
    book_list = paginator.get_page(page)
    return render(request,"index.html",locals())
django分页示例(包含页数多时解决办法)

总结,分页时需要做三件事:

  • 创建处理分页数据的类
  • 根据分页数据获取数据
  • 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]

 

======================================another========================================

 

Django作为Python Web开发框架的一哥,提供了企业级网站开发所需要的几乎所有功能,其中就包括自带分页功能。利用Django自带的Paginator类,我们可以很轻松地实现分页。Django 2.0和1.X最大的不同在于新增了get_page()方法。我们现在来具体看看有什么不同。

Django 1.X 和Django 2.0下实现分页

利用Django实现分类非常简单,我们只需要修改views.py和模板template。Django 1.X下实现分页代码如下:

# app/views.py - 基于函数的视图

 1 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 2 from .models import Article
 3 from django.shortcuts import render
 4 
 5 def article_list(request):
 6     article_list = Article.objects.all()
 7     paginator = Paginator(article_list, 10)  # 实例化一个分页对象, 每页显示10个
 8 
 9     page = request.GET.get('page')  # 从URL通过get页码,如?page=3
10     try:
11         articles = paginator.page(page)  # 获取某页对应的记录
12     except PageNotAnInteger:  # 如果页码不是个整数
13         articles = paginator.page(1)  # 提取第一页的记录
14     except EmptyPage:  # 如果页码太大,没有相应的记录
15         articles = paginator.page(paginator.num_pages)  # 提取最后一页的记录
16 
17     return render(request, 'article_list.html', {'articles': articles})
View Code

你注意到没有?上段代码的try和2个except非常重要,但是看上去有些冗余。Django 2.0下新增了get_page()方法,可以将代码大大简化(如下图所示)。它所实现的功能与上面是一样的。当用户提交的页码不是整数时,提取第一页记录。当用户输入的页码太大时,只提取最后一页记录。

 1 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 2 from .models import Article
 3 from django.shortcuts import render
 4 
 5 def article_list(request):
 6     article_list = Article.objects.all()
 7     paginator = Paginator(article_list, 10)  # 实例化一个分页对象, 每页显示10个
 8 
 9     page = request.GET.get('page')  # 从URL通过get页码,如?page=3
10    articles = paginator.get_page(page)  # 获取某页对应的记录, 如果
11     
12     return render(request, 'article_list.html', {'articles': articles})
View Code

Django 1.X和2.0下的模板是一样的。这里提供两种显示方案。

模板一: 上一页, Page 1 of 3, 下一页

#app/templates/app/article_list.html

 1 {% for article in articles %} 
 2     {{ article.title }}  
 3 {% endfor %}
 4 
 5 <div class="pagination">
 6     <span class="step-links">
 7         {% if articles.has_previous %}
 8             <a href="?page=1">&laquo; first</a>
 9             <a href="?page={{ articles.previous_page_number }}">previous</a>
10         {% endif %}
11 
12         <span class="current">
13             Page {{ articles.number }} of {{ articles.paginator.num_pages }}.
14         </span>
15 
16         {% if articles.has_next %}
17             <a href="?page={{ articles.next_page_number }}">next</a>
18             <a href="?page={{ articles.paginator.num_pages }}">last &raquo;</a>
19         {% endif %}
20     </span>
21 </div>
View Code

模板二: Page 1, 2, 3, 4, 5, 6, 7, 8, ... (推荐)

#app/templates/app/article_list.html

 1 # Pagination style 2
 2 {% for article in articles %}
 3     {{ article.title }}
 4 {% endfor %}
 5 <div class="pagination">
 6 <nav>
 7     <ul class="pagination">
 8         {% if articles.has_previous %}
 9         <li class="">
10         <a href="?page={{ articles.previous_page_number }}" aria-label="Previous">
11         <span aria_hidden="true">&laquo;</span></a>
12         </li>
13         {% endif %}
14         
15         {% for page_num in articles.paginator.page_range %}
16             {% if page_num == articles.number %}
17          <li class="active"><a href="?page={{ page_num }}">{{page_num}}</a> </li>
18             {% else %}
19          <li class=""><a href="?page={{ page_num }}">{{page_num}}</a> </li>
20             {% endif %}
21         {% endfor %}
22         
23         {% if articles.has_next %}
24          <li class="">
25               <a href="?page={{ articles.next_page_number }}" aria-label="Next">
26                   <span aria_hidden="true">&raquo;</span></a>
27         </li>
28       {% endif %}
29     </ul>
30 </nav>
31 </div>
View Code

Django如何在基于类的视图里使用分页?

 

上述案例里我们使用了函数试图,很容易定义page对象, 并传递给模板,例如articles。但是如果我们希望使用基于类的视图,我们该如何实现分页呢?其实操作非常简单。我们只需在视图中加入paginate_by = number即可。

from. models import Article
from django.views.generic import ListView

class ArticleListView(ListView):
    model = Article  # 等于 queryset = models.Article.objects.all()
    template_name = 'app/article_list.html'  # 可选的
    context_object_name = "article_list"    # 默认context名字
    paginate_by = 10  # 每页10项
View Code

此时模板article_list.html也需要做出相应调整,如下图所示。Django会先对是否分页is_paginated做个判断,如果有,就会自动生成个page_obj分页对象传递到模板。

 1 {% if article_list %}
 2     {% for article in article_list %}
 3     {{ article.title }}
 4     {% endfor %}
 5 
 6     {% if is_paginated %}
 7     <ul class="pagination">
 8     {% if page_obj.has_previous %}
 9     <li>
10         <span><a href="?page={{ page_obj.previous_page_number }}">Previous</a></span>
11     </li>
12     {% endif %}
13     <li class="">
14         <span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</span>
15     </li>
16     {% if page_obj.has_next %}
17           <li>
18         <span><a href="?page={{ page_obj.next_page_number }}">Next</a></span>
19     </li>
20     {% endif %}
21     </ul>
22 
23 {% else %}
24     <h3>Articles</h3>
25     <p>No article yet</p>
26 {% endif %}
View Code

django自定义分页

自定义分页封装在类中,使用时调用示例:

 1 class PagerHelper:
 2     def __init__(self,total_count,current_page,base_url,per_page=10):
 3         self.total_count = total_count
 4         self.current_page = current_page
 5         self.base_url = base_url
 6         self.per_page = per_page
 7 
 8     @property
 9     def db_start(self):
10         return (self.current_page -1) * self.per_page
11 
12     @property
13     def db_end(self):
14         return self.current_page * self.per_page
15 
16     def total_page(self):
17         v, a = divmod(self.total_count, self.per_page)
18         if a != 0:
19             v += 1
20         return v
21 
22     def pager_str(self):
23 
24         v = self.total_page()
25 
26         pager_list = []
27         if self.current_page == 1:
28             pager_list.append('<a href="javascript:void(0);">上一页</a>')
29         else:
30             pager_list.append('<a href="%s?p=%s">上一页</a>' % (self.base_url, self.current_page - 1,))
31 
32         # 6,1:12
33         # 7,2:13
34         if v <= 11:
35             pager_range_start = 1
36             pager_range_end = v
37         else:
38             if self.current_page < 6:
39                 pager_range_start = 1
40                 pager_range_end = 11 + 1
41             else:
42                 pager_range_start = self.current_page - 5
43                 pager_range_end = self.current_page + 5 + 1
44                 if pager_range_end > v:
45                     pager_range_start = v - 10
46                     pager_range_end = v + 1
47 
48         for i in range(pager_range_start, pager_range_end):
49             if i == self.current_page:
50                 pager_list.append('<a class="active" href="%s?p=%s">%s</a>' % (self.base_url, i, i,))
51             else:
52                 pager_list.append('<a href="%s?p=%s">%s</a>' % (self.base_url, i, i,))
53 
54         if self.current_page == v:
55             pager_list.append('<a href="javascript:void(0);">下一页</a>')
56         else:
57             pager_list.append('<a href="%s?p=%s">下一页</a>' % (self.base_url, self.current_page + 1,))
58 
59         pager = "".join(pager_list)
60         return pager
utils page.py
    <div class="pagination">
        {{ str_pager|safe }}
    </div>
html
 1 from django.shortcuts import render,redirect,HttpResponse
 2 from app01 import models
 3 from utils.page import PagerHelper
 4 
 5 def handle_classes(request):
 6     if request.method == "GET":
 7         current_page = request.GET.get('p',1)
 8         current_page = int(current_page)
 9 
10         # 所有数据的个数
11         total_count = models.Classes.objects.all().count()
12         obj = PagerHelper(total_count, current_page, '/classes.html',5)
13         pager = obj.pager_str()
14 
15         cls_list = models.Classes.objects.all()[obj.db_start:obj.db_end]
16 
17         current_user = request.session.get('username')
18         return render(request,
19                       'classes.html',
20                       {'username': current_user, 'cls_list': cls_list, 'str_pager': pager})
21 
22 
23     elif request.method == "POST":
24         # Form表单提交的处理方式
25         """
26         caption = request.POST.get('caption',None)
27         if caption:
28             models.Classes.objects.create(caption=caption)
29         return redirect('/classes.html')
30         """
31         # Ajax
32         import json
33 
34         response_dict = {'status': True, 'error': None, 'data': None}
35 
36         caption = request.POST.get('caption', None)
37         print(caption)
38         if caption:
39             obj = models.Classes.objects.create(caption=caption)
40             response_dict['data'] = {'id': obj.id, 'caption': obj.caption}
41         else:
42             response_dict['status'] = False
43             response_dict['error'] = "标题不能为空"
44         return HttpResponse(json.dumps(response_dict))
view.py

未封装版:

  • 优点:直观
  • 缺点:代码乱,不易维护,可拓展性差
     1 data = []
     2  
     3 for i in range(1, 302):
     4     tmp = {"id": i, "name": "alex-{}".format(i)}
     5     data.append(tmp)
     6  
     7 print(data)
     8  
     9  
    10 def user_list(request):
    11  
    12     # user_list = data[0:10]
    13     # user_list = data[10:20]
    14     try:
    15         current_page = int(request.GET.get("page"))
    16     except Exception as e:
    17         current_page = 1
    18  
    19     per_page = 10
    20  
    21     # 数据总条数
    22     total_count = len(data)
    23     # 总页码
    24     total_page, more = divmod(total_count, per_page)
    25     if more:
    26         total_page += 1
    27  
    28     # 页面最多显示多少个页码
    29     max_show = 11
    30     half_show = int((max_show-1)/2)
    31  
    32     if current_page <= half_show:
    33         show_start = 1
    34         show_end = max_show
    35     else:
    36         if current_page + half_show >= total_page:
    37             show_start = total_page - max_show
    38             show_end = total_page
    39         else:
    40             show_start = current_page - half_show
    41             show_end = current_page + half_show
    42  
    43     # 数据库中获取数据
    44     data_start = (current_page - 1) * per_page
    45     data_end = current_page * per_page
    46  
    47     user_list = data[data_start:data_end]
    48  
    49     # 生成页面上显示的页码
    50     page_html_list = []
    51     # 加首页
    52     first_li = '<li><a href="/user_list/?page=1">首页</a></li>'
    53     page_html_list.append(first_li)
    54     # 加上一页
    55     if current_page == 1:
    56         prev_li = '<li><a href="#">上一页</a></li>'
    57     else:
    58         prev_li = '<li><a href="/user_list/?page={}">上一页</a></li>'.format(current_page - 1)
    59     page_html_list.append(prev_li)
    60     for i in range(show_start, show_end+1):
    61         if i == current_page:
    62             li_tag = '<li class="active"><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
    63         else:
    64             li_tag = '<li><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
    65         page_html_list.append(li_tag)
    66  
    67     # 加下一页
    68     if current_page == total_page:
    69         next_li = '<li><a href="#">下一页</a></li>'
    70     else:
    71         next_li = '<li><a href="/user_list/?page={}">下一页</a></li>'.format(current_page+1)
    72     page_html_list.append(next_li)
    73  
    74     # 加尾页
    75     page_end_li = '<li><a href="/user_list/?page={}">尾页</a></li>'.format(total_page)
    76     page_html_list.append(page_end_li)
    77  
    78     page_html = "".join(page_html_list)
    79  
    80     return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})
    View Code

封装版:

  • 优点:易维护、可拓展性强
  • 缺点:逻辑相对复杂
     1 """
     2 自定义分页组件
     3 """
     4 class Pagination(object):
     5  
     6     def __init__(self, data_num, current_page, url_prefix, per_page=10,  max_show=11):
     7         """
     8         进行初始化.
     9         :param data_num: 数据总数
    10         :param current_page: 当前页
    11         :param url_prefix: 生成的页码的链接前缀
    12         :param per_page: 每页显示多少条数据
    13         :param max_show: 页面最多显示多少个页码
    14         """
    15         self.data_num = data_num
    16         self.per_page = per_page
    17         self.max_show = max_show
    18         self.url_prefix = url_prefix
    19  
    20         # 把页码数算出来
    21         self.page_num, more = divmod(data_num, per_page)
    22         if more:
    23             self.page_num += 1
    24  
    25         try:
    26             self.current_page = int(current_page)
    27         except Exception as e:
    28             self.current_page = 1
    29             # 如果URL传过来的页码数是负数
    30         if self.current_page <= 0:
    31             self.current_page = 1
    32             # 如果URL传过来的页码数超过了最大页码数
    33         elif self.current_page > self.page_num:
    34             self.current_page = self.page_num  # 默认展示最后一页
    35  
    36         # 页码数的一半 算出来
    37         self.half_show = max_show // 2
    38  
    39         # 页码最左边显示多少
    40         if self.current_page - self.half_show <= 1:
    41             self.page_start = 1
    42             self.page_end = self.max_show
    43         elif self.current_page + self.half_show >= self.page_num:  # 如果右边越界
    44             self.page_end = self.page_num
    45             self.page_start = self.page_num - self.max_show
    46         else:
    47             self.page_start = self.current_page - self.half_show
    48             # 页码最右边显示
    49             self.page_end = self.current_page + self.half_show
    50  
    51         if self.page_num < self.page_end:
    52             self.page_end = self.page_num  # 如果总页面小于结束页面,那么结束页面即为总页码
    53  
    54     @property
    55     def start(self):
    56         # 数据从哪儿开始切
    57         return (self.current_page - 1) * self.per_page
    58  
    59     @property
    60     def end(self):
    61         # 数据切片切到哪儿
    62         return self.current_page * self.per_page
    63  
    64     def page_html(self):
    65         # 生成页码
    66         l = []
    67         # 加一个首页
    68         l.append('<li><a href="{}?page=1">首页</a></li>'.format(self.url_prefix))
    69         # 加一个上一页
    70         if self.current_page == 1:
    71             l.append('<li class="disabled" ><a href="#">«</a></li>'.format(self.current_page))
    72         else:
    73             l.append('<li><a href="{}?page={}">«</a></li>'.format(self.url_prefix, self.current_page - 1))
    74  
    75  
    76         for i in range(self.page_start, self.page_end + 1):
    77  
    78             if i == self.current_page:
    79                 tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
    80             else:
    81                 tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
    82             l.append(tmp)
    83  
    84         # 加一个下一页
    85         if self.current_page == self.page_num:
    86             l.append('<li class="disabled"><a href="#">»</a></li>'.format(self.current_page))
    87         else:
    88             l.append('<li><a href="{}?page={}">»</a></li>'.format(self.url_prefix, self.current_page + 1))
    89         # 加一个尾页
    90         l.append('<li><a href="{}?page={}">尾页</a></li>'.format(self.url_prefix, self.page_num))
    91         return "".join(l)
    View Code 

 封装版使用步骤:

  1. 将上面的一段代码复制到自定义的模块(pt文件)中
  2. 导入自定义模块
  3. 在views系统的函数里写入以下代码
    def user_list(request):
        # 实例化一个分页类的对象
        obj = Pagination(blogs.count(),page,'blogs.html')
        # 根据传入的总博客数、页码获取当页需要展示的博客
        blog_list = blogs[obj.start:obj.end]
        # 根据传入的博客数及页码获取生成分页的html格式的页码列表
        page_html = pager.page_html()
        #返回指定页面
        return render(request, "blog_list.html", {"blog_list": blog_list, "page_html": page_html})
    View Code
  4. 在需要生成页面的html页面写入以下代码
    <div class="topicListFooter fenye">
         <ul class="pagination">
             {{ page_html|safe }}
          </ul>
     </div>
    View Code

    注:示例中用的是bootstrap分页样式

Django中的内置分页(不能展示页码列表)

 1 from django.shortcuts import render
 2 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 3  
 4 L = []
 5 for i in range(999):
 6     L.append(i)
 7  
 8 def index(request):
 9     current_page = request.GET.get('p')
10  
11     paginator = Paginator(L, 10)
12     # per_page: 每页显示条目数量
13     # count:    数据总个数
14     # num_pages:总页数
15     # page_range:总页数的索引范围,如: (1,10),(1,200)
16     # page:     page对象
17     try:
18         posts = paginator.page(current_page)
19         # has_next              是否有下一页
20         # next_page_number      下一页页码
21         # has_previous          是否有上一页
22         # previous_page_number  上一页页码
23         # object_list           分页之后的数据列表
24         # number                当前页
25         # paginator             paginator对象
26     except PageNotAnInteger:
27         posts = paginator.page(1)
28     except EmptyPage:
29         posts = paginator.page(paginator.num_pages)
30     return render(request, 'index.html', {'posts': posts})
内置分页view部分
 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8 <ul>
 9     {% for item in posts %}
10         <li>{{ item }}</li>
11     {% endfor %}
12 </ul>
13  
14 <div class="pagination">
15       <span class="step-links">
16         {% if posts.has_previous %}
17             <a href="?p={{ posts.previous_page_number }}">Previous</a>
18         {% endif %}
19           <span class="current">
20             Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
21           </span>
22           {% if posts.has_next %}
23               <a href="?p={{ posts.next_page_number }}">Next</a>
24           {% endif %}
25       </span>
26  
27 </div>
28 </body>
29 </html>
内置分页HTML部分
posted on 2019-05-29 17:23  始终不够啊  阅读(679)  评论(0编辑  收藏  举报