分页
一、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})
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})
<!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>
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})
<!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>
二、自定义分页
""" 分页组件使用示例: 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)
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())
<!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>
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())
总结,分页时需要做三件事:
- 创建处理分页数据的类
- 根据分页数据获取数据
- 输出分页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})
你注意到没有?上段代码的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})
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">« 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 »</a> 19 {% endif %} 20 </span> 21 </div>
模板二: 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">«</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">»</span></a> 27 </li> 28 {% endif %} 29 </ul> 30 </nav> 31 </div>
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项
此时模板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 %}
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
<div class="pagination"> {{ str_pager|safe }} </div>
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))
未封装版:
- 优点:直观
- 缺点:代码乱,不易维护,可拓展性差
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})
封装版:
- 优点:易维护、可拓展性强
- 缺点:逻辑相对复杂
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)
封装版使用步骤:
- 将上面的一段代码复制到自定义的模块(pt文件)中
- 导入自定义模块
- 在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})
- 在需要生成页面的html页面写入以下代码
<div class="topicListFooter fenye"> <ul class="pagination"> {{ page_html|safe }} </ul> </div>
注:示例中用的是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})
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>