Django框架补充之分页器推导
2251 字
11 分钟
Django框架补充之分页器推导
- 1纯手撸Web框架
- 2Python框架初识
- 3Django框架初识
- 4Django框架安装
- 5Django框架入门之小白必会三板斧
- 6Django便捷函数shortcuts
- 7Django框架入门之静态文件
- 8Django的静态文件
- 9Django框架入门之request对象
- 10Django框架入门之ORM操作
- 11Django框架之生命周期流程图
- 12Django框架之路由层
- 13Django框架之视图层
- 14Django框架之模板层
- 15Django框架之模型层
- 16图书管理系统
- 17Ajax基础操作
- 18Ajax进阶操作
- 19JS确认插件补充
- 20Django框架之序列化组件serializers
- 21Django框架之批量插入数据
- 22Django框架补充之分页器推导本文
- 23Django框架之Form组件
- 24Django框架Form组件之常用字段及插件
- 25Django框架Form组件之渲染HTML代码
- 26Django框架Form组件之渲染错误信息
- 27Django框架Form组件之钩子函数(Hook)
- 28Django框架Form组件之源码
- 29Django框架Form组件之模型表单ModelForm
- 30Django表单API详解
- 31Django框架之Cookie和Session
- 32Django框架之会话session补充
- 33Django框架之CBV添加装饰器的三种方式
- 34Django框架之中间件引入
- 35Django框架之中间件思想
- 36Django框架之csrf跨站请求
- 37Django框架之auth模块
- 38Django框架之settings源码
- 39Django框架之settings配置
- 40Django框架之settings核心配置项
- 41RBAC权限系统
- 42前端基础之URL编码
【一】引入
- 针对上一小节批量插入的数据
- 我们在前端展示的时候发现一个很严重的问题
- 一页展示了所有的数据,数据量太大,查看不方便
- 针对数据量大但又需要全部展示给用户观看的情况下
- 我们统一做法都是做分页处理
【二】分页推导
【1】理论
- 首先我们需要明确的时候
- get请求也是可以携带参数的
- 所以我们在朝后端发送查看数据的同时可以携带一个参数告诉后端我们想看第几页的数据
- 其次我们还需要知道一个点
- queryset对象是支持索引取值和切片操作的
- 但是不支持负数索引情况
【2】分析
- 后端分析
# 获取用户想访问的页码 如果没有 默认展示第一页current_page = request.GET.get("page",1)
# 由于后端接受到的前端数据是字符串类型所以我们这里做类型转换处理加异常捕获try: current_page = int(current_page)except Exception as e: current_page = 1
# 还需要定义页面到底展示几条数据per_page_num = 10 # 一页展示10条数据
# 需要对总数据进行切片操作 需要确定切片起始位置和终止位置start_page = ?end_page = ?- 下面需要研究current_page、per_page_num、start_page、end_page四个参数之间的数据关系
per_page_num = 10current_page start_page end_page 1 0 10 2 10 20 3 20 30 4 30 40
per_page_num = 5current_page start_page end_page 1 0 5 2 5 10 3 10 15 4 15 20- 可以很明显的看出规律
start_page = (current_page - 1) * per_page_numend_page = current_page* per_page_num【三】手动切片
【1】后端
def ab_many(request):
# 分页操作 推导
# (1) 支持切片models.Book.objects.all()[1:20] --- 展示前20条数据 # (2) 分页操作 # 想访问的页数 current_page = request.GET.get('page', 1) # 如果获取不到当前页码就展示第一页 # 异常捕获 try: current_page = int(current_page) except Exception: current_page = 1 # 每页展示多少条 per_page_num = 10 # 起始位置 start_page = (current_page - 1) * per_page_num # 终止位置 end_page = current_page * per_page_num # 切片 book_queryset = models.Book.objects.all()[start_page:end_page] ''' start_page = (current_page-1) * per_page_num end_page = current_page * per_page_num ''' return render(request, 'ab_many.html', locals())【2】前端
{% for book_obj in book_queryset %} <p>{{ book_obj.title }}</p>{% endfor %}【3】路由访问
通过在 url 后面携带参数,完成分页操作http://127.0.0.1:8000/ab_many/?page=3但是这种当时方式,没有对前端页面进行优化,仅仅只是后端部分完成了分页
【四】分页器组件
【1】参考bootstrap
- 参考bootstrap官方文档,拷贝分页器代码进行优化
<nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li><a href="#">1</a></li> <li><a href="#">2</a></li> <li><a href="#">3</a></li> <li><a href="#">4</a></li> <li><a href="#">5</a></li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul></nav>【2】优化后代码
{% for book_obj in book_queryset %} <p>{{ book_obj.title }}</p>{% endfor %}
<nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li><a href="?page=1">1</a></li> <li><a href="?page=2">2</a></li> <li><a href="?page=3">3</a></li> <li><a href="?page=4">4</a></li> <li><a href="?page=5">5</a></li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul></nav>- 效果
- 通过点击底部的页码也已进行指定的分页
缺点:数据页数只能指定,无法展示全部数据
【五】动态计算页数
【1】引入
- 当我问你下面几个问题的时候,你的内心肯定是鄙视的,不信的话那就请听题
- 问题1<总数据有100条>总数据有100条>,每页展示10条,总共需要几页?
- 答案<10条>10条>
- 问题2<总数据有101条>总数据有101条>,每页展示10条,总共需要几页?
- 答案<11条>11条>
- 问题3<如何通过代码算出到底需要多少条>如何通过代码算出到底需要多少条>?
- 答案<去你妹的>去你妹的>,不会!!!
【2】计算题
- 总数据 100 条
- 每一页 10 条
- 需要 10 页
- 每一页 10 条
- 总数据 99 条
- 每一页 10 条
- 需要 10 页
- 每一页 10 条
- 总数据 101 条
- 每一页 10 条
- 需要 11 页
- 每一页 10 条
如何动态的计算出需要多少页?
【3】内置方法之divmod
(1)介绍
- 内置函数divmod(x, y)
- 用于执行整数除法和取模运算,并返回一个包含商和余数的元组。
- 参数x和y是两个数字
- x 是被除数
- y 是除数。
- 以下是divmod()函数的使用示例:
result = divmod(9, 2)print(result) # 输出 (4, 1)
result = divmod(14, 3)print(result) # 输出 (4, 2)
# 余数只要不是0就需要在第一个数字上加一- 在第一个示例中,我们将9除以2,得到商4和余数1。
- 在第二个示例中,我们将14除以3,得到商4和余数2。
- divmod()函数对于需要同时获得商和余数的情况非常有用。
- 它可以用于计算进制转换、时间单位转换等问题。
(2)实战
def ab_many(request):
# 分页操作 推导
# (1) 支持切片models.Book.objects.all()[1:20] --- 展示前20条数据 # (2) 分页操作 # 书籍对象 book_query = models.Book.objects.all() # 想访问的页数 current_page = request.GET.get('page', 1) # 如果获取不到当前页码就展示第一页 # 异常捕获 try: current_page = int(current_page) except Exception: current_page = 1 # 每页展示多少条 per_page_num = 10 # 动态计算出需要的总页数 all_count = book_query.count() # 计算总数 page_count, more = divmod(all_count, per_page_num) # 判断元祖的第二个数字是否为0,从而确定到底需要多少页来展示数据 if more: page_count += 1
page_html = '' # 前端动态页面展示 - 后端写好页面传给前端 for count in range(1, page_count + 1): page_html += f'<li><a href="?page={count}">{count}</a></li>'
# 起始位置 start_page = (current_page - 1) * per_page_num # 终止位置 end_page = current_page * per_page_num # 切片 book_queryset = book_query[start_page:end_page] ''' start_page = (current_page-1) * per_page_num end_page = current_page * per_page_num ''' return render(request, 'ab_many.html', locals())- 前端
{% for book_obj in book_queryset %} <p>{{ book_obj.title }}</p>{% endfor %}
<nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {# 前段转义 - 将后端的html页面进行转义,转为前端页码/也可以后端做这件事 #} {{ page_html|safe }} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul></nav>完成了分页操作的雏形,但是问题是前端页面展示的页码过于繁多
【六】美化分页器
【1】引入
上面是自定义分页器开发流程的基本思路
- 我们不需要掌握代码的编写,
- 只需要掌握基本用法即可
【2】示例
- 在制作页码个数的时候,一般情况下是奇数个
- 符合中国人的审美
def ab_many(request):
# 分页操作 推导
# (1) 支持切片models.Book.objects.all()[1:20] --- 展示前20条数据 # (2) 分页操作 # 书籍对象 book_query = models.Book.objects.all() # 想访问的页数 current_page = request.GET.get('page', 1) # 如果获取不到当前页码就展示第一页 # 异常捕获 try: current_page = int(current_page) except Exception: current_page = 1 # 每页展示多少条 per_page_num = 10 # 动态计算出需要的总页数 all_count = book_query.count() # 计算总数 page_count, more = divmod(all_count, per_page_num) if more: page_count += 1
# 纠正左侧负数页的问题 left_page_count = current_page if current_page < 6: current_page = 6 page_html = '' # 前端动态页面展示 - 后端写好页面传给前端 for count in range(current_page - 5, current_page + 6): if left_page_count == count: # 第一页高亮显示 page_html += f'<li class="active"><a href="?page={count}" >{count}</a></li>' else: page_html += f'<li><a href="?page={count}" >{count}</a></li>' # 起始位置 start_page = (current_page - 1) * per_page_num # 终止位置 end_page = current_page * per_page_num # 切片 book_queryset = book_query[start_page:end_page] ''' start_page = (current_page-1) * per_page_num end_page = current_page * per_page_num ''' return render(request, 'ab_many.html', locals())- 前端
{% for book_obj in book_queryset %} <p>{{ book_obj.title }}</p>{% endfor %}
<nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {# 前段转义 - 将后端的html页面进行转义,转为前端页码/也可以后端做这件事 #} {{ page_html|safe }} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul></nav>【七】封装分页器
【1】自定义分页器封装代码
class Pagination(object): def __init__(self, current_page, all_count, per_page_num=2, pager_count=11): """ 封装分页相关数据 :param current_page: 当前页 :param all_count: 数据库中的数据总条数 :param per_page_num: 每页显示的数据条数 :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
# 总页码 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 = [] # 添加前面的nav和ul标签 page_html_list.append(''' <nav aria-label='Page navigation>' <ul class='pagination'> ''') first_page = '<li><a href="?page=%s">首页</a></li>' % (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="?page=%s">上一页</a></li>' % (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="?page=%s">%s</a></li>' % (i, i,) else: temp = '<li><a href="?page=%s">%s</a></li>' % (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="?page=%s">下一页</a></li>' % (self.current_page + 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) # 尾部添加标签 page_html_list.append(''' </nav> </ul> ''') return ''.join(page_html_list)【2】自定义分页器使用示例
(1)后端
def get_book(request): book_list = models.Book.objects.all() current_page = request.GET.get("page",1) all_count = book_list.count() page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10) page_queryset = book_list[page_obj.start:page_obj.end] return render(request,'booklist.html',locals())(2)前端
<div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for book in page_queryset %} <p>{{ book.title }}</p> {% endfor %} {{ page_obj.page_html|safe }} </div> </div></div>支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!
相关文章智能推荐
1
C 语言发展史
编程语言了解 C 语言从 BCPL、B 语言到现代标准 C 的发展历程、核心特点与应用领域。
2
C 语言开发环境的安装与配置
编程语言在 Windows、Linux 与 macOS 上安装 C 工具链,配置编辑器,并编译运行第一个 C 程序。
3
C 语言初识:程序运行机制与基本结构
编程语言认识 C 程序从源代码到运行的完整流程,以及基础语法和程序的基本结构。
4
C 语言基础:注释、关键字、变量与数据类型
编程语言学习 C 语言的注释、关键字、标识符、常量、变量和基本数据类型等基础知识。
5
C 语言数据类型
编程语言理解 C 语言的数据类型体系,包括基本类型、整数类型、浮点类型和逻辑类型。
随机文章随机推荐














