day71
参考:http://www.cnblogs.com/liwenzhou/p/8660826.html#autoid-4-1-0
day71
参考:http://www.cnblogs.com/liwenzhou/p/8343243.html#autoid-0-4-5
分页
当数据库中数据有很多,我们通常会在前端页面做分页展示。
分页的数据可以在前端页面实现,也可以在后端实现分页。
后端实现分页的原理就是每次只请求一页数据。
准备工作
我们使用脚本批量创建一些测试数据(将下面的代码保存到bulk_create.py文件中放到Django项目的根目录,直接执行即可。):
1 import os 2 3 if __name__ == "__main__": 4 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings") 5 6 import django 7 django.setup() 8 9 from app01 import models 10 bulk_obj = (models.Publisher(name='沙河第{}出版社'.format(i)) for i in range(300)) 11 models.Publisher.objects.bulk_create(bulk_obj)
不分页
分页代码分析:
数据格式:
显示内容部分:
导航条部分:
导航条样式
完整代码:
books.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>书籍列表</title> 6 <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> 7 </head> 8 <body> 9 <div class="container"> 10 <table class="table table-bordered"> 11 <thread> 12 <tr> 13 <th>序号</th> 14 <th>id</th> 15 <th>书名</th> 16 </tr> 17 </thread> 18 <tbody> 19 {% for book in books %} 20 <tr> 21 <td>{{ forloop.counter }}</td> 22 <td>{{ book.id }}</td> 23 <td>{{ book.title }}</td> 24 </tr> 25 {% endfor %} 26 27 </tbody> 28 </table> 29 <nav aria-label="Page navigation"> 30 <ul class="pagination"> 31 <li> 32 33 34 <li> 35 {{ page_html|safe }} 36 </li> 37 38 </li> 39 </ul> 40 </nav> 41 </div> 42 43 </body> 44 </html>
views.py
1 def books(request): 2 # 从url取参数 3 page_num = request.GET.get("page") # url中拿到 4 page_num = int(page_num) 5 6 # 以上决定的是页面显示的内容 7 # 一下决定导航条的内容 8 # 每一页显示多少条数据 9 per_page = 10 10 # 总数据条数 11 total_count = models.Book.objects.all().count() 12 # 总共需要多少页码显示 13 total_page, m = divmod(total_count, per_page) # 共total_count条数据, 每页per_page条显示 14 if m: # 有值 需加1 15 total_page += 1 # 共需total_count+=1页显示 16 try: 17 page_num = int(page_num) 18 # 如果页数超过最大页码数,返回最后一页 19 if page_num > total_page: 20 page_num = total_page 21 if page_num < 1: 22 page_num = 1 23 except Exception as e: 24 page_num = 1 25 26 # 定义两个变量 27 data_start = (page_num - 1) * 10 28 data_end = page_num * 10 29 all_book = models.Book.objects.all()[data_start:data_end] 30 31 # 页面上总共展示多少页码 32 max_page = 11 33 if total_page < max_page: # 总页数过小,小于设定 34 max_page = total_page 35 half_max_page = max_page // 2 36 # 页面上展示的页码从哪开始 37 page_start = page_num - half_max_page 38 # 到哪儿结束 39 page_end = page_num + half_max_page 40 # 如果起始值小于等于1 41 if page_start <= 1: 42 page_start = 1 43 page_end = max_page 44 # 如果当前页加一半比总页码数还大 45 if page_end >= total_page: 46 page_end = total_page 47 page_start = total_page - max_page + 1 # 导航条显示数量必须相同 48 49 50 51 # 自己拼接分页的HTML代码 52 html_str_list = [] 53 # 加上第一页 54 html_str_list.append('<li><a href="/books/?page=1">首页</a></li>') 55 # 加上一个上一页的标签 只要中间页往前移就整体往前移一页 56 #html_str_list.append('<li><a href="/books/?page={}"><span aria-hidden="true">«</span></a></li>'.format(page_num-1)) 57 if page_num == 1: # 如果已经是第一页了就不在跳转 # 58 html_str_list.append( 59 '<li class="disabled"><a href="#"><span aria-hidden="true">«</span></a></li>') 60 else: 61 html_str_list.append( 62 '<li><a href="/books/?page={}"><span aria-hidden="true">«</span></a></li>'.format(page_num - 1)) 63 for i in range(page_start, page_end+1): 64 # # 跳转内容带 page 巧妙! page决定了显示哪些内容在页面上 65 if i == page_num: 66 # 当前页高亮 67 tmp = '<li class="active"><a href="/books/?page={0}">{0}</a></li>'.format(i) 68 else: 69 tmp = '<li><a href="/books/?page={0}">{0}</a></li>'.format(i) 70 html_str_list.append(tmp) 71 # 加上一个下一页的标签 只要中间页往前移就整体往前移一页 72 if page_num == total_page: # 如果已经是最后一页了就不在跳转 # 73 html_str_list.append( 74 '<li class="disabled"><a href="#"><span aria-hidden="true">»</span></a></li>') 75 else: 76 html_str_list.append( 77 '<li><a href="/books/?page={}"><span aria-hidden="true">»</span></a></li>'.format(page_num + 1)) 78 # 加上尾页 79 html_str_list.append('<li><a href="/books/?page={}">尾页</a></li>'.format(total_page)) 80 page_html = "".join(html_str_list) 81 return render(request, "books.html", {"books": all_book, "page_html": page_html})
将以上内容封装成通用模块
@property
以下为完整程序:
views.py
def depts(request): # 从URL取参数 page_num = request.GET.get("page") print(page_num, type(page_num)) # 总数据是多少 total_count = models.Dept.objects.all().count() from utils.mypage import Page # 调用自己写的模块 # 创建对象 page_obj = Page(page_num, total_count, per_page=10, url_prefix="/depts/", max_page=11, ) ret = models.Dept.objects.all()[page_obj.start:page_obj.end] # 调用该对象中的方法 print(ret) # 使用对象方法 page_html = page_obj.page_html() return render(request, "dept.html", {"depts": ret, "page_html": page_html})
mypage.py
1 class Page(): 2 # 路径 3 def __init__(self, page_num, total_count, url_prefix, per_page=10, max_page=11): 4 """ 5 6 :param page_num: 当前页码数 7 :param total_count: 数据总数 8 :param url_prefix: a标签href的前缀 9 :param per_page: 每页显示多少条数据 10 :param max_page: 页面上最多显示几个页码 11 """ 12 self.url_prefix = url_prefix 13 self.max_page = max_page 14 # 每一页显示多少条数据 15 # 总共需要多少页码来展示 16 total_page, m = divmod(total_count, per_page) 17 if m: 18 total_page += 1 19 self.total_page = total_page 20 21 try: 22 page_num = int(page_num) 23 # 如果输入的页码数超过了最大的页码数,默认返回最后一页 24 if page_num > total_page: 25 page_num = total_page 26 except Exception as e: 27 # 当输入的页码不是正经数字的时候 默认返回第一页的数据 28 page_num = 1 29 self.page_num = page_num 30 31 # 定义两个变量保存数据从哪儿取到哪儿 决定显示的数据 32 self.data_start = (page_num - 1) * 10 33 self.data_end = page_num * 10 34 35 # 页面上总共展示多少页码 36 if total_page < self.max_page: 37 self.max_page = total_page 38 39 half_max_page = self.max_page // 2 40 # 页面上展示的页码从哪儿开始 41 page_start = page_num - half_max_page 42 # 页面上展示的页码到哪儿结束 43 page_end = page_num + half_max_page 44 # 如果当前页减一半 比1还小 45 if page_start <= 1: 46 page_start = 1 47 page_end = self.max_page 48 # 如果 当前页 加 一半 比总页码数还大 49 if page_end >= total_page: 50 page_end = total_page 51 page_start = total_page - self.max_page + 1 52 self.page_start = page_start 53 self.page_end = page_end 54 55 @property # page_obj.start 表示返回数据本身 56 def start(self): # 这部分是显示内容的部分,并不是导航条的部分 显示数据的开始与结束 57 return self.data_start 58 59 @property 60 def end(self): 61 return self.data_end 62 63 64 def page_html(self): 65 # 自己拼接分页的HTML代码 66 html_str_list = [] 67 # 加上第一页 68 html_str_list.append('<li><a href="{}?page=1">首页</a></li>'.format( self.url_prefix)) 69 70 # 判断一下 如果是第一页,就没有上一页 71 if self.page_num <= 1: 72 html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">«</span></a></li>'.format(self.page_num-1)) 73 else: 74 # 加一个上一页的标签 75 html_str_list.append('<li><a href="{}?page={}"><span aria-hidden="true">«</span></a></li>'.format( self.url_prefix, self.page_num-1)) 76 77 for i in range(self.page_start, self.page_end+1): 78 # 如果是当前页就加一个active样式类 79 if i == self.page_num: #路径和页码 80 tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i) 81 else: 82 tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format( self.url_prefix, i) 83 84 html_str_list.append(tmp) 85 86 # 加一个下一页的按钮 87 # 判断,如果是最后一页,就没有下一页 88 if self.page_num >= self.total_page: 89 html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">»</span></a></li>') 90 else: 91 html_str_list.append('<li><a href="{}?page={}"><span aria-hidden="true">»</span></a></li>'.format( self.url_prefix, self.page_num+1)) 92 # 加最后一页 93 html_str_list.append('<li><a href="{}?page={}">尾页</a></li>'.format( self.url_prefix, self.total_page)) 94 95 page_html = "".join(html_str_list) 96 return page_html
含三个方法,前两个获得显示数据的起始与结束,第三个获得导航条需要显示的内容。
dept.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>部门列表</title> 6 <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> 7 </head> 8 <body> 9 10 <div class="container"> 11 <table class="table table-bordered"> 12 <thead> 13 <tr> 14 <th>序号</th> 15 <th>id</th> 16 <th>部门名</th> 17 </tr> 18 </thead> 19 <tbody> 20 {% for dept in depts %} 21 <tr> 22 <td>{{ forloop.counter }}</td> 23 <td>{{ dept.id }}</td> 24 <td>{{ dept.name }}</td> 25 </tr> 26 {% endfor %} 27 28 </tbody> 29 </table> 30 <nav aria-label="Page navigation"> 31 <ul class="pagination"> 32 {{ page_html|safe }} 33 </ul> 34 </nav> 35 </div> 36 </body> 37 </html>
效果: