Django框架-管理后台项目之分页实现
一、自定义分页
分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应在数据库表中的起始位置。
1、设定煤业显示的数据条数
2、用户输入页码(第一页,第二页...)
3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
4、在数据表中根据起始位置取值,页面上输出数据
前面那样会在页面中生成所有的页码,但实际需要是设定指定数量的页码,格式如 [上一页][1][2][3][4][5][下一页]
1、设定每页显示数据条数
2、用户输入页码
3、设定显示多少页号
4、获取当前数据总条数
5、根据设定显示多少页号和数据总条数计算出总页数
6、根据设定的每页显示条数和当前页码数,计算出需要取数据表的起始位置
7、在数据表中根据起始位置取值,页面上输出数据
8、输出分页html,如:[上一页][1][2][3][4][5][下一页]
urls.py
urlpatterns = [ url(r'page/, views.page), ]
customer.html
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="{% static 'imgs/aimp_logo_48px_.ico' %}"> {% block title %} {#下面的是改网页的标题上的图标#} <title>Template</title> {% endblock %} <!-- Bootstrap core CSS --> <link href="{% static 'plugin/bootstrap3.7/css/bootstrap.min.css' %}" rel="stylesheet"> <!-- font_awesome CSS --> <link rel="stylesheet" href="{% static 'plugin/font-awesome-4.7.0/css/font-awesome.min.css' %}"> <!-- Custom styles for this template网上模板定义的css样式 --> <link href="{% static 'css/dashboard.css' %}" rel="stylesheet"> {% block custom_css %} {#自定义css留白#} {% endblock %} </head> <body> {#导航组件#} {% include 'layout/navbar.html' %} {#内容区#} <div class="container-fluid"> <div class="row"> {#左侧边栏#} <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li class="active"><a href="{% url 'app_crm:customer_list' %}">客户信息表 <span class="sr-only">(current)</span></a></li> <li><a href="#">销售</a></li> <li><a href="#">老师</a></li> <li><a href="#">学生</a></li> </ul> </div> {#右边内容展示区,表单及面板#} <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> {% block content %} <h2 class="sub-header">客户信息展示表</h2> <div class="table-responsive"> <table class="table table-striped"> <thead> <tr> <th>序号</th> <th>账户</th> <th>密码</th> </tr> </thead> <tbody> {% for u in user %} <tr> <td>{{ forloop.counter }}</td> <td>{{ u.name }}</td> <td>{{ u.pwd }}</td> </tr> {% empty %} <tr> <td colspan="3" class="text-center">暂无数据</td> </tr> {% endfor %} </tbody> </table> {# 分页 #} <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for page in total_page %} {# 此处也可以设计url为分组的形式传递页码给后台{% url 'app_crm:base' page %}#} <li><a href="{% url 'app_crm:base' %}?page={{ page }}">{{ page }}</a></li> {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </div> {% endblock %} </div> </div> </div> <!-- Bootstrap core JavaScript --> <!-- Placed at the end of the document so the pages load faster --> <script type="text/javascript" src="{% static 'plugin/jquery-3.3.1/jquery3.3.1.min.js' %}"></script> <script type="text/javascript" src="{% static 'plugin/bootstrap3.7/js/bootstrap.min.js' %}"></script> {#自定义js留白区域快#} {% block custom_js %} {% endblock %} </body> </html>
views.py
1 def page(request): 2 """ 3 all_count: 总数据条数 4 page_num: 每页显示数据条数,自定义 5 total_page: 总页码数 6 more:总数据条数% 每页数 ==》余数 7 current_page: 当前页码,由前端点击时,将页码发回来 8 """ 9 user = [{'name': 'sun%s' % i, 'pwd': 'pwd{}'.format(i)} for i in range(1, 302)] # 测试数据源 10 all_count = len(user) # 拿到总数据条数 11 page_num = 10 # 定义每页显示的数据条数 12 total_page, more = divmod(all_count, page_num) # 得出商和余数 13 if more: # 如果有余数,表示总页码要多加一个页码,否则就是整除 14 total_page += 1 15 16 try: 17 current_page = int(request.GET.get('page')) 18 if current_page <= 0: # 因为不确定前端传过来的数字的准确性,可能没有或超过,负数所以要判断,一旦报错,就设置当前页为1 19 raise ValueError() 20 except Exception as e: 21 current_page = 1 22 23 # 所有数据和生成的标签页全部展示 24 # 因为计划通过前端for循环产生标签,故需要传一个可迭代的数据即range(1,total_page+1),切片取头不取尾 25 return render(request, 'layout/base.html', {'user': user, 'total_page': range(1, total_page + 1)}) 26 27 # 注:前端拿到user和total_page对象,对其for循环生成对应标签即可
1 def page(request): 2 """ 3 all_count: 总数据条数 4 page_num: 每页显示数据条数,自定义 5 total_page: 总页码数 6 more:总数据条数% 每页数 ==》余数 7 current_page: 当前页码,由前端点击时,将页码发回来 8 start: 切片开始索引 9 end: 切片结束索引 10 页码数和切片之间的关系: 11 第一页: 1 1 10 0 10 每页10条,切片从0开始,尾不取 12 2 11 20 10 20 13 3 21 30 20 30 14 关系为:(当前页-1)*10 即 start = (current_page-1)*10 15 end= current_page*page_num 16 """ 17 user = [{'name': 'sun%s' % i, 'pwd': 'pwd{}'.format(i)} for i in range(1, 302)] 18 all_count = len(user) 19 page_num = 10 # 定义每页显示的数据条数 20 total_page, more = divmod(all_count, page_num) # 得出商和余数 21 if more: # 如果有余数,表示总页码要多加一个页码,否则就是整除 22 total_page += 1 23 try: 24 current_page = int(request.GET.get('page')) 25 # 因为不确定前端传过来的数字的准确性,可能没有或超过,负数所以要判断,一旦报错,就设置当前页为1 26 if current_page <= 0: 27 raise ValueError() 28 except Exception as e: 29 current_page = 1 30 # 根据前端传过来的页码,计算给前端发送多少数据,限制数据条数 31 start = (current_page - 1) * 10 32 end = current_page * page_num 33 34 return render(request, 'layout/base.html', {'user': user[start:end], # 限制数据条数,根据需要给 35 'total_page': range(1, total_page + 1)})
def page(request): """ all_count: 总数据条数 page_num: 每页显示数据条数,自定义 total_page: 总页码数 more:总数据条数% 每页数 ==》余数 current_page: 当前页码,由前端点击时,将页码发回来 start: 切片开始索引 end: 切片结束索引 页码数和切片之间的关系: 第一页: 1 1 10 0 10 每页10条,切片从0开始,尾不取 2 11 20 10 20 3 21 30 20 30 关系为:(当前页-1)*10 即 start_page = (current_page-1)*10 end_page = current_page*page_num start_page: 起始页码数 end_page: 终止页码数 max_page_show: 每页最多展示几个分页,如7各分页:1 2 3 当前页 5 6 7 """ user = [{'name': 'sun%s' % i, 'pwd': 'pwd{}'.format(i)} for i in range(1, 302)] all_count = len(user) page_num = 10 # 定义每页显示的数据条数 total_page, more = divmod(all_count, page_num) # 得出商和余数 if more: # 如果有余数,表示总页码要多加一个页码,否则就是整除 total_page += 1 # 因为计划通过前端for循环产生标签,故需要传一个可迭代的数据即range(1,total_page+1),切片取头不取尾 try: current_page = int(request.GET.get('page')) # 因为不确定前端传过来的数字的准确性,可能没有或超过,负数所以要判断,一旦报错,就设置当前页为1 if current_page <= 0: raise ValueError() except Exception as e: current_page = 1 # 根据前端传过来的页码,计算给前端发送多少数据,限制数据条数 start = (current_page - 1) * 10 end = current_page * page_num # 定义分页页码起始页码数,终止页码数,每个页面最大显示页码数 max_page_show = 5 # 一般都定义为奇数,让中间的页(即当前页)左右对称 half_page_show = max_page_show // 2 # 将会出现几种情况: # 1、数据总页码数<= 定义的每个页面最大显示页码数max_page_show,就直接把所有的显示出来即可 if total_page <= max_page_show: start_page = 1 end_page = total_page else: # 2、当前页小于half_page_show时,排除会出现负数的情况,解决左边的问题 if current_page <= half_page_show: # 都要保证每个页面有max_page_show页 start_page = 1 end_page = max_page_show # 3、当前页+half_page_show > max_page_show 时,会出现没有数据,但会有页码,故需要排除掉 elif current_page + half_page_show > total_page: start_page = total_page - max_page_show + 1 # start_page = current_page - half_page_show +1 end_page = total_page else: start_page = current_page - half_page_show end_page = current_page + half_page_show return render(request, 'layout/base.html', {'user': user[start:end], 'total_page': range(start_page, end_page + 1) }) # 限制页面总显示页码数及根据需求页码给出对应数据
from django.shortcuts import render, reverse def base(request): """ all_count: 总数据条数 page_num: 每页显示数据条数,自定义 total_page: 总页码数 more:总数据条数% 每页数 ==》余数 current_page: 当前页码,由前端点击时,将页码发回来 start: 切片开始索引 end: 切片结束索引 页码数和切片之间的关系: 第一页: 1 1 10 0 10 每页10条,切片从0开始,尾不取 2 11 20 10 20 3 21 30 20 30 关系为:(当前页-1)*10 即 start_page = (current_page-1)*10 end_page = current_page*page_num start_page: 起始页码数 end_page: 终止页码数 max_page_show: 每个页面最大显示页码数,如7各分页:1 2 3 当前页 5 6 7 """ user = [{'name': 'sun%s' % i, 'pwd': 'pwd{}'.format(i)} for i in range(1, 302)] all_count = len(user) # 得出数据总条数 page_num = 10 # 定义每页显示的数据条数 total_page, more = divmod(all_count, page_num) # 得出商和余数 if more: total_page += 1 # 如果有余数,表示总页码要多加一个页码 try: current_page = int(request.GET.get('page')) # 因为不确定前端传过来的数字的准确性,可能没有或超过,负数,所以要判断,一旦报错,就设置当前页为1 if current_page <= 0: raise Exception('当前页码数字不符合规范') except Exception as e: current_page = 1 # 根据前端传过来的页码,计算给前端发送多少数据,限制数据条数 start = (current_page - 1) * page_num end = current_page * page_num # 定义分页页码起始页码数,终止页码数,每个页面最大显示页码数,实现每页固定页码数 max_page_show = 5 # 一般都定义为奇数,让中间的页(即当前页)左右对称 half_page_show = max_page_show // 2 # 1、数据总页码数<= 定义的每个页面最大显示页码数max_page_show,就直接把所有的显示出来即可 if total_page <= max_page_show: start_page = 1 end_page = total_page else: # 2、当前页小于half_page_show时,排除会出现负数的情况,解决左边的问题 if current_page <= half_page_show: # 都要保证每个页面有max_page_show页 start_page = 1 end_page = max_page_show # 3、当前页+half_page_show > max_page_show 时,会出现没有数据,但会有页码,故需要排除掉 elif current_page + half_page_show > total_page: start_page = total_page - max_page_show + 1 # start_page = current_page - half_page_show +1 end_page = total_page else: start_page = current_page - half_page_show end_page = current_page + half_page_show """后端实现分页,前端只需接收只需接收字符串即可,故需要把生成得标签拼接起来""" html_list = [] # 加上"首页"功能,即当前页与第一页相比【首页】【上一页】 1 2 3 4 5 【下一页】【末页】 if current_page <= 1: first = '<li class="disabled"><a>首页</a></li>' else: first = '<li><a href="{}?page={}">首页</a></li>'.format(reverse('app_crm:base'), 1) html_list.append(first) # 加上"上一页"功能,即当前页与第一页相比 【首页】【上一页】 1 2 3 4 5 【下一页】【末页】 if current_page <= 1: prev = '<li class="disabled"><a>上一页</a></li>' # 当前页小于1时,上一页按钮禁止点击 else: prev = '<li><a href="{}?page={}">上一页</a></li>'.format(reverse('app_crm:base'), current_page - 1) html_list.append(prev) # 生成分页页码标签 for page in range(start_page, end_page + 1): if page == current_page: # 加active类 li_html = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(reverse('app_crm:base'), page) else: li_html = '<li><a href="{0}?page={1}">{1}</a></li>'.format(reverse('app_crm:base'), page) html_list.append(li_html) # 加上"下一页"功能,当前页与最后一页比较,即total_page if current_page >= total_page: next_page = '<li class="disabled"><a>下一页</a></li>' else: next_page = '<li><a href="{}?page={}">下一页</a></li>'.format(reverse('app_crm:base'), current_page + 1) html_list.append(next_page) # 加上"末页" 功能 if current_page >= total_page: last = '<li class="disabled"><a>末页</a></li>' else: last = '<li><a href="{}?page={}">末页</a></li>'.format(reverse('app_crm:base'), total_page) html_list.append(last) html_str = "".join(html_list) # 拼接成字符串 from django.utils.html import format_html # 后端声明发送的是安全的标签,将字符串编译成标签 result = format_html(html_str) return render(request, 'layout/base.html', {'user': user[start:end], 'total_page': result }) # 限制页面总显示页码数及根据需求页码给出对应数据
分页终极版是在后端循环生成分页标签,故前端只需引用即可{{result}} 即可。
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <link rel="icon" href="{% static 'imgs/aimp_logo_48px_.ico' %}"> {% block title %} <title>Template</title> {% endblock %} <!-- Bootstrap core CSS --> <link href="{% static 'plugin/bootstrap3.7/css/bootstrap.min.css' %}" rel="stylesheet"> <!-- font_awesome CSS --> <link rel="stylesheet" href="{% static 'plugin/font-awesome-4.7.0/css/font-awesome.min.css' %}"> <!-- Custom styles for this template网上模板定义的css样式 --> <link href="{% static 'css/dashboard.css' %}" rel="stylesheet"> {% block custom_css %} {#自定义css留白#} {% endblock %} </head> <body> {#导航组件#} {% include 'layout/navbar.html' %} {#内容区#} <div class="container-fluid"> <div class="row"> {#左侧边栏#} <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li class="active"><a href="{% url 'app_crm:customer_list' %}">客户信息表 <span class="sr-only">(current)</span></a></li> <li><a href="#">销售</a></li> <li><a href="#">老师</a></li> <li><a href="#">学生</a></li> </ul> </div> {#右边内容展示区#} <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> {% block content %} <h2 class="sub-header">客户信息展示表</h2> <div class="table-responsive"> <table class="table table-striped"> <thead> <tr> <th>序号</th> <th>账户</th> <th>密码</th> </tr> </thead> <tbody> {% for u in user %} <tr> <td>{{ forloop.counter }}</td> <td>{{ u.name }}</td> <td>{{ u.pwd }}</td> </tr> {% empty %} <tr> <td colspan="3" class="text-center">暂无数据</td> </tr> {% endfor %} </tbody> </table> {# 分页 #} <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> {{ total_page }} </ul> <form action=""> <span>去第</span> <label for="search_page"></label> <input id="search_page" name="page" type="text" > <span>页</span> <input type="submit" class=" btn-primary" value="确定"> </form> </nav> </div> {% endblock %} </div> </div> </div> <script type="text/javascript" src="{% static 'plugin/jquery-3.3.1/jquery3.3.1.min.js' %}"></script> <script type="text/javascript" src="{% static 'plugin/bootstrap3.7/js/bootstrap.min.js' %}"></script> {% block custom_js %} {#自定义js留白区域快#} {% endblock %} </body> </html>
二、分页功能模块化,封装成一个类,供所有的页面使用
在项目下建立一个包如utils,在里面建立一个py文件,如命名分页组件: pagination.py
封装成分页组件,需要导入传参即可用
"""分页组件""" from django.utils.html import format_html # 后端声明发送的是安全的标签,将字符串编译成标签 class Pagination(object): """ all_count: 总数据条数 page_num: 每页显示数据条数,自定义 total_page: 总页码数 more:总数据条数% 每页数 ==》余数 current_page: 当前页码,由前端点击时,将页码发回来 start: 切片开始索引 end: 切片结束索引 页码数和切片之间的关系: 第一页: 1 1 10 0 10 每页10条,切片从0开始,尾不取 2 11 20 10 20 3 21 30 20 30 关系为:(当前页-1)*10 即 start_page = (current_page-1)*10 end_page = current_page*page_num start_page: 起始页码数 end_page: 终止页码数 max_page_show: 每个页面最大显示页码数,如7各分页:1 2 3 当前页 5 6 7 一般都定义为奇数,让中间的页(即当前页)左右对称 base_url : 访问url地址 """ def __init__(self, request, base_url, all_count, page_num=10, max_page_show=5): # 获取需求页码 try: current_page = int(request.GET.get('page')) if current_page <= 0: raise Exception('当前页码数字不符合规范') except Exception as e: current_page = 1 # 定义分页页码起始页码数,终止页码数,每个页面最大显示页码数,实现每页固定页码数 self.max_page_show = max_page_show self.half_page_show = max_page_show // 2 self.current_page = current_page self.all_count = all_count self.page_num = page_num self.base_url = base_url # 计算数据总条数 self.total_page, more = divmod(self.all_count, self.page_num) # 得出商和余数 if more: self.total_page += 1 # 如果有余数,表示总页码要多加一个页码 @property def start(self): # 根据前端传过来的页码,计算给前端发送多少数据,限制数据条数 # 数据切片的起始索引和终止索引 return (self.current_page - 1) * self.page_num @property def end(self): return self.current_page * self.page_num @property def html_str(self): # 计算起始页码数和终止页码数 # 1、数据总页码数<= 定义的每个页面最大显示页码数max_page_show,就直接把所有的显示出来即可 if self.total_page <= self.max_page_show: start_page = 1 end_page = self.total_page else: # 2、当前页小于half_page_show时,排除会出现负数的情况,解决左边的问题 if self.current_page <= self.half_page_show: # 都要保证每个页面有max_page_show页 start_page = 1 end_page = self.max_page_show # 3、当前页+half_page_show > max_page_show 时,会出现没有数据,但会有页码,故需要排除掉 elif self.current_page + self.half_page_show > self.total_page: start_page = self.total_page - self.max_page_show + 1 # start_page = current_page - half_page_show +1 end_page = self.total_page else: start_page = self.current_page - self.half_page_show end_page = self.current_page + self.half_page_show """后端实现分页,前端只需接收只需接收字符串即可,故需要把生成得标签拼接起来""" html_list = [] # 加上"首页"功能,即当前页与第一页相比【首页】【上一页】 1 2 3 4 5 【下一页】【末页】 if self.current_page <= 1: first = '<li class="disabled"><a>首页</a></li>' else: first = '<li><a href="{}?page={}">首页</a></li>'.format(self.base_url, 1) html_list.append(first) # 加上"上一页"功能,即当前页与第一页相比 【首页】【上一页】 1 2 3 4 5 【下一页】【末页】 if self.current_page <= 1: prev = '<li class="disabled"><a><上一页></a></li>' # 当前页小于1时,上一页按钮禁止点击 else: prev = '<li><a href="{}?page={}"><上一页></a></li>'.format(self.base_url, self.current_page - 1) html_list.append(prev) # 生成分页页码标签 for page in range(start_page, end_page + 1): if page == self.current_page: # 加active类 li_html = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, page) else: li_html = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, page) html_list.append(li_html) # 加上"下一页"功能,当前页与最后一页比较,即total_page if self.current_page >= self.total_page: next_page = '<li class="disabled"><a><下一页></a></li>' else: next_page = '<li><a href="{}?page={}"><下一页></a></li>'.format(self.base_url, self.current_page + 1) html_list.append(next_page) # 加上"末页" 功能 if self.current_page >= self.total_page: last = '<li class="disabled"><a>末页</a></li>' else: last = '<li><a href="{}?page={}">末页</a></li>'.format(self.base_url, self.total_page) html_list.append(last) html_str = "".join(html_list) # 拼接成字符串 result = format_html(html_str) return result
此分页组件,项目下所有的app都可以使用,主要传参 request, base_url, all_count, page_num=10, max_page_show=5,
分别为request,目标url,所有的数据条数,每页显示最大数据条数,默认10条,每页最多显示分页标签数,默认5个
在app应用的views.py中引用:
from utils.pagination import Pagination
def base_test(request): base_url = request.path_info # 获取当前url,也可以自定义 page_obj = Pagination(request, base_url, len(users), 15, 11) total_page = page_obj.total_page return render(request, 'layout/base.html', {'user_list': users[page_obj.start:page_obj.end], 'result': page_obj.html_str, 'total_page':total_page })
三、终极版:将搜索条件和标签页码放到url下,让标签显示的是筛选后的数据进行分页
"""分页组件""" from django.utils.html import format_html # 后端声明发送的是安全的标签,将字符串编译成标签 class Pagination(object): """ all_count: 总数据条数 page_num: 每页显示数据条数,自定义 total_page: 总页码数 more:总数据条数% 每页数 ==》余数 current_page: 当前页码,由前端点击时,将页码发回来 start: 切片开始索引 end: 切片结束索引 页码数和切片之间的关系: 第一页: 1 1 10 0 10 每页10条,切片从0开始,尾不取 2 11 20 10 20 3 21 30 20 30 关系为:(当前页-1)*10 即 start_page = (current_page-1)*10 end_page = current_page*page_num start_page: 起始页码数,一个页面中显示的分页标签 end_page: 终止页码数 max_page_show: 每个页面最大显示页码数,如7各分页:1 2 3 当前页 5 6 7 一般都定义为奇数,让中间的页(即当前页)左右对称 base_url : 当前访问url地址 query_params: 为了分页标签能带上搜索条件,让分页数据是从搜索条件来的 搜索和分页要合并起来,不然搜索到对应数据,展示出来,但一旦点击分页标签,就会走分页的逻辑,不是拿搜索中的数据 来分页,所以应该为分页标签加上搜索条件,当发点击搜索get请求后,会先走搜索,将筛选后的数据类表传给分页函数,再分页, 当点击分页标签时会再次搜索,然后分页,而不是搜索条件为空,展示所有的数据 """ def __init__(self, request, base_url, all_count, page_num=10, max_page_show=5): # 获取需求页码 try: current_page = int(request.GET.get('page')) if current_page <= 0: raise Exception('当前页码数字不符合规范') except Exception as e: current_page = 1 # 定义分页页码起始页码数,终止页码数,每个页面最大显示页码数,实现每页固定页码数 self.max_page_show = max_page_show self.half_page_show = max_page_show // 2 self.current_page = current_page self.all_count = all_count self.page_num = page_num self.base_url = base_url # 为了分页与搜索条件合并 # request.GET.urlencode() 方法可以将url中?后面的查询条件按key=value完成拿出来 query=3 # url合成格式为:?query=3&page=x # import copy # query_params = copy.deepcopy(request.GET) # 是一个querySet字典,为防止对request.GET 的改变影响其它方法的调用,对其深拷贝 # django自带的深拷贝方法 query_params = request.GET.copy() self.query_params = query_params self.query_params._mutable = True # 允许querySet字典变更 # 计算数据总条数 self.total_page, more = divmod(self.all_count, self.page_num) # 得出商和余数 if more: self.total_page += 1 # 如果有余数,表示总页码要多加一个页码 @property def start(self): # 根据前端传过来的页码,计算给前端发送多少数据,限制数据条数 # 数据切片的起始索引和终止索引 return (self.current_page - 1) * self.page_num @property def end(self): return self.current_page * self.page_num @property def html_str(self): # 计算起始页码数和终止页码数 # 1、数据总页码数<= 定义的每个页面最大显示页码数max_page_show,就直接把所有的显示出来即可 if self.total_page <= self.max_page_show: start_page = 1 end_page = self.total_page else: # 2、当前页小于half_page_show时,排除会出现负数的情况,解决左边的问题 if self.current_page <= self.half_page_show: # 都要保证每个页面有max_page_show页 start_page = 1 end_page = self.max_page_show # 3、当前页+half_page_show > max_page_show 时,会出现没有数据,但会有页码,故需要排除掉 elif self.current_page + self.half_page_show > self.total_page: start_page = self.total_page - self.max_page_show + 1 # start_page = current_page - half_page_show +1 end_page = self.total_page else: start_page = self.current_page - self.half_page_show end_page = self.current_page + self.half_page_show """后端实现分页,前端只需接收只需接收字符串即可,故需要把生成得标签拼接起来""" html_list = [] # 加上"首页"功能,即当前页与第一页相比【首页】【上一页】 1 2 3 4 5 【下一页】【末页】 if self.current_page <= 1: first = '<li class="disabled"><a>首页</a></li>' else: self.query_params['page'] = 1 # first = '<li><a href="{}?page={}">首页</a></li>'.format(self.base_url, 1) # 为了search和page合并将page加入到query_params字典中,然后query_params.urlencode()拼接 first = '<li><a href="{}?{}">首页</a></li>'.format(self.base_url, self.query_params.urlencode()) html_list.append(first) # 加上"上一页"功能,即当前页与第一页相比 【首页】【上一页】 1 2 3 4 5 【下一页】【末页】 if self.current_page <= 1: prev = '<li class="disabled"><a><上一页></a></li>' # 当前页小于1时,上一页按钮禁止点击 else: self.query_params['page'] = self.current_page - 1 prev = '<li><a href="{}?{}"><上一页></a></li>'.format(self.base_url, self.query_params.urlencode()) html_list.append(prev) # 生成分页页码标签 for page in range(start_page, end_page + 1): self.query_params['page'] = page if page == self.current_page: # 加active类 li_html = '<li class="active"><a href="{}?{}">{}</a></li>'.format(self.base_url, self.query_params.urlencode(), page) else: li_html = '<li><a href="{}?{}">{}</a></li>'.format(self.base_url, self.query_params.urlencode(), page) html_list.append(li_html) # 加上"下一页"功能,当前页与最后一页比较,即total_page if self.current_page >= self.total_page: next_page = '<li class="disabled"><a><下一页></a></li>' else: self.query_params['page'] = self.current_page + 1 next_page = '<li><a href="{}?{}"><下一页></a></li>'.format(self.base_url, self.query_params.urlencode()) html_list.append(next_page) # 加上"末页" 功能 if self.current_page >= self.total_page: last = '<li class="disabled"><a>末页</a></li>' else: self.query_params['page'] = self.total_page last = '<li><a href="{}?{}">末页</a></li>'.format(self.base_url, self.query_params.urlencode()) html_list.append(last) html_str = "".join(html_list) # 拼接成字符串 result = format_html(html_str) return result
四、django 实现分页下一页序号自增
在django模板中分页时使用{{forloop.counter }}生成序号时,点击下一页,序号依旧从1开始
{% for row in user_set%} <li>{{forloop.counter}}--{{ row.username }}</li> {% endfor %}
解决办法:views.py向模板发送
strat=(current_page-1)*count_page
#current_page为当前页码数,count_page为每页显示数量
#其实已经在自定义分页写好了,只用拿来发送给模板就可以
render(request,"user_info.html",{"user_set": date,"strat":strat}) 此时模板中的{{forloop.counter }}改为{{forloop.counter|add:strat }} 就可以实现在第二页之后每一页自增
class ConsultRecordList(BatchOperationMethod): def get(self, request, *args, customer_id='0', ): query_list = ['note'] q = self.multi_search_conditions(request, query_list) if customer_id == '0': # 规定customer_id =0,拿所有记录 from django.db.models import Max # 获取用户最后的一条记录 customer_last_record_list = models.ConsultRecord.objects.filter(q, consultant=request.user).values( 'customer').annotate(Max('id')) consult_record_info_list = [] for i in customer_last_record_list: # 获取每个客户最后跟进记录的对象 recod_obj = models.ConsultRecord.objects.filter(id=i['id__max']).first() consult_record_info_list.append(recod_obj) else: consult_record_info_list = models.ConsultRecord.objects.filter( q, consultant=request.user, customer_id=customer_id ).order_by('-date') # 添加 add_btn, next_url = self.get_add_btn(request, reverse('consult_record_add')) # 分页 page_obj = Pagination(request, reverse('consult_record', args=(customer_id,)), len(consult_record_info_list), settings.PAGE_MAX_SHOW, settings.PAGE_NUM ) return render(request, 'customer/consult_records.html', {'consult_record_info_list': consult_record_info_list[page_obj.start:page_obj.end], 'html_str': page_obj.html_str, 'total_page': page_obj.total_page, 'start': page_obj.start, 'add_btn': add_btn, 'next_url': next_url} )