前戏
分页是我们经常遇到的,只要有表单,数据量大的时候,都要用到分页,所以说分页是web开发里必不可少的知识点。
分页第一版
使用列表生成式来制造一些数据
user_data = [{'name':'zouzou{}'.format(i),'pwd':'abc{}'.format(i)} for i in range(1,303)]
在写个视图函数,把数据传给html文件进行渲染
def user_list(request): return render(request, 'user_list.html', {'data': user_data})
写一个HTML文件用于展示数据
user_list.html
{% extends 'layout.html' %}是继承母版,下面写的自己的内容。这样的效果是所有的数据都显示在了一页,肯定不是我们想要的结果。在来改写一下视图函数
def user_list(request): try: current_page = int(request.GET.get('page',1)) # 获取表单里提交的页码,默认为1 if current_page <= 0: current_page = 1 except Exception as e: current_page = 1 par_num = 10 # 每页显示的数量 all_count = len(user_data) # 总数据量 total_num, more=divmod(all_count,par_num) # 页码数和余数 if more: # 有余数,页码加1 total_num += 1 start = (current_page-1) * par_num # 每页的开始值 end = current_page * par_num # 每页的结束值 return render(request, 'user_list.html', {'data': user_data[start:end], "total_num":range(1, total_num+1)})
"total_num":range(1, total_num+1)} 给HTMl文件,方便渲染
修改对应的html文件
{% extends 'layout.html' %} {% block content %} <table class="table table-bordered"> <thead> <th>序号</th> <th>账号</th> <th>密码</th> </thead> <tbody> {% for user in data %} <tr> <td>{{ forloop.counter }}</td> <td>{{ user.name }}</td> <td>{{ user.pwd }}</td> </tr> {% endfor %} </tbody> </table> <nav sria-label="Page navigation"> <ul class="pagination"> {% for num in total_num %} <li><a href="/user_list/?page={{ num }}">{{ num }}</a></li> {% endfor %} </ul> </nav> {% endblock content %}
刷新页面查看效果
分页第二版(指定页码个数)
只需要更改视图函数就可以了
# 分页 def user_list(request): try: current_page = int(request.GET.get('page',1)) # 获取表单里提交的页码,默认为1 if current_page <= 0: current_page = 1 except Exception as e: current_page = 1 max_show = 11 # 最多显示的页码数 half_show = max_show // 2 # 左右显示的个数 page_start = current_page - half_show # 开始的页码为当前页码减掉一半 page_end = current_page + half_show # 结束页码 par_num = 10 # 每页显示的数量 all_count = len(user_data) # 总数据量 total_num, more=divmod(all_count,par_num) # 页码数和余数 if more: # 有余数,页码加1 total_num += 1 ''' 做判断,要不然点第一页,显示了负数,点最后一页,还往上加 ''' # 总页码数小于最大显示数,显示总页码数 if total_num <= max_show: page_start = 1 page_end = max_show else: # 总页码数大于最大显示数,最多显示11个 if current_page <= half_show: page_start = 1 page_end = max_show elif current_page+half_show >= total_num: page_start = total_num-max_show+1 page_end = total_num else: page_start = current_page - half_show page_end = current_page + half_show start = (current_page-1) * par_num # 每页的开始值 end = current_page * par_num # 每页的结束值 return render(request, 'user_list.html', {'data': user_data[start:end], "total_num":range(page_start, page_end+1)})
分页第三版(增加下一页,上一页,首页,尾页)
把html里循环展示页码的代码在服务端实现
def user_list(request): try: current_page = int(request.GET.get('page',1)) # 获取表单里提交的页码,默认为1 if current_page <= 0: current_page = 1 except Exception as e: current_page = 1 max_show = 11 # 最多显示的页码数 half_show = max_show // 2 # 左右显示的个数 page_start = current_page - half_show # 开始的页码为当前页码减掉一半 page_end = current_page + half_show # 结束页码 par_num = 10 # 每页显示的数量 all_count = len(user_data) # 总数据量 total_num, more=divmod(all_count,par_num) # 页码数和余数 if more: # 有余数,页码加1 total_num += 1 ''' 做判断,要不然点第一页,显示了负数,点最后一页,还往上加 ''' # 总页码数小于最大显示数,显示总页码数 if total_num <= max_show: page_start = 1 page_end = max_show else: # 总页码数大于最大显示数,最多显示11个 if current_page <= half_show: page_start = 1 page_end = max_show elif current_page+half_show >= total_num: page_start = total_num-max_show+1 page_end = total_num else: page_start = current_page - half_show page_end = current_page + half_show # 存放li标签的列表 html_list = [] first_li = '<li><a href="/user_list/?page=1">首页</a></li>' html_list.append(first_li) if current_page == 1: prev_li = '<li class="disabled"><a><<</a></li>' else: prev_li = '<li><a href="/user_list/?page={0}"><<</a></li>'.format(current_page - 1) html_list.append(prev_li) for num in range(page_start, page_end + 1): if current_page == num: li_html = '<li class="active"><a href="/user_list/?page={0}">{0}</a></li>'.format(num) else: li_html = '<li><a href="/user_list/?page={0}">{0}</a></li>'.format(num) html_list.append(li_html) if current_page == total_num: next_li = '<li class="disabled"><a>>></a></li>' else: next_li = '<li><a href="/user_list/?page={0}">>></a></li>'.format(current_page + 1) html_list.append(next_li) last_li = '<li><a href="/user_list/?page={}">尾页</a></li>'.format(total_num) html_list.append(last_li) html_str = mark_safe(''.join(html_list)) start = (current_page-1) * par_num # 每页的开始值 end = current_page * par_num # 每页的结束值 return render(request, 'user_list.html', {'data': user_data[start:end], "total_num":range(page_start, page_end+1), 'html_str': html_str})
最后一版
前面写的三版,分页的代码都在一个视图函数里面,如果别的页面页要用到的话,我们还要复制一遍,这样代码显的很low,我们可以在我们项目下面新建一个文件夹utils,在新建一个py文件,把我们分页的代码写到里面
""" 分页器 """ from django.utils.safestring import mark_safe class Pagination: def __init__(self, request, all_count, per_num=10, max_show=11): # 基本的URL self.base_url = request.path_info # 当前页码 try: self.current_page = int(request.GET.get('page', 1)) if self.current_page <= 0: self.current_page = 1 except Exception as e: self.current_page = 1 # 最多显示的页码数 self.max_show = max_show half_show = max_show // 2 # 每页显示的数据条数 self.per_num = per_num # 总数据量 self.all_count = all_count # 总页码数 self.total_num, more = divmod(all_count, per_num) if more: self.total_num += 1 # 总页码数小于最大显示数:显示总页码数 if self.total_num <= max_show: self.page_start = 1 self.page_end = self.total_num else: # 总页码数大于最大显示数:最多显示11个 if self.current_page <= half_show: self.page_start = 1 self.page_end = max_show elif self.current_page + half_show >= self.total_num: self.page_end = self.total_num self.page_start = self.total_num - max_show + 1 else: self.page_start = self.current_page - half_show self.page_end = self.current_page + half_show @property def start(self): return (self.current_page - 1) * self.per_num @property def end(self): return self.current_page * self.per_num @property def show_li(self): # 存放li标签的列表 html_list = [] first_li = '<li><a href="{}?page=1">首页</a></li>'.format(self.base_url) html_list.append(first_li) if self.current_page == 1: prev_li = '<li class="disabled"><a><<</a></li>' else: prev_li = '<li><a href="{1}?page={0}"><<</a></li>'.format(self.current_page - 1, self.base_url) html_list.append(prev_li) for num in range(self.page_start, self.page_end + 1): if self.current_page == num: li_html = '<li class="active"><a href="{1}?page={0}">{0}</a></li>'.format(num, self.base_url) else: li_html = '<li><a href="{1}?page={0}">{0}</a></li>'.format(num, self.base_url) html_list.append(li_html) if self.current_page == self.total_num: next_li = '<li class="disabled"><a>>></a></li>' else: next_li = '<li><a href="{1}?page={0}">>></a></li>'.format(self.current_page + 1, self.base_url) html_list.append(next_li) last_li = '<li><a href="{1}?page={0}">尾页</a></li>'.format(self.total_num, self.base_url) html_list.append(last_li) return mark_safe(''.join(html_list))
在视图函数里面调用
def user_list(request): page = Pagination(request, len(users)) return render(request, 'user_list.html', { "data": users[page.start:page.end], # 'total_num': range(page_start, page_end + 1) 'html_str': page.show_li })
# 展示客户列表 def customer_list(request): all_customer = models.Customer.objects.all() page = Pagination(request, all_customer.count()) return render(request, 'crm/customer_list.html', {"all_customer": all_customer[page.start:page.end], 'pagination': page.show_li})