簡單的分頁功能
urls.py
urlpatterns = [ url(r'^page/', views.page,name='page'), ]
views.py
users = [{"name": f"alex{i}", "pwd": "dsb"} for i in range(1, 355)] def page(request): user_list = users try: page = int(request.GET.get('page', 1)) if page <= 0: page = 1 except Exception: page = 1 """ 索引切片 page 起始 終止 1 0 10 2 10 20 3 20 30 """ # 每頁展示的數據 per_num = 10 # 數據切片起始值 start = (page - 1) * per_num # 數據切片終止值 end = page * per_num # 總數據條數 page_count = len(user_list) # 總頁碼數 sum_page, more = divmod(page_count, per_num) if more: sum_page += 1 # 前端循環的a標簽的值 num = [i for i in range(1, sum_page + 1)] user_list = user_list[start:end] return render(request, 'page.html', locals())
html.py(bootstrap樣式中的分頁組件)
<div class="form-group col-sm-7"> <table class="table table-hover table-bordered"> <thead> <tr> <th>name</th> <th>pwd</th> </tr> </thead> <tbody> {% for user in user_list %} <tr> <td>{{ user.name }}</td> <td>{{ user.pwd }}</td> </tr> {% endfor %} </tbody> </table> </div> <div class="pull-left form-group col-sm-7"> <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for n in num %} <li><a href="{% url 'page' %}?page={{ n }}">{{ n }}</a></li> {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </div>
效果:簡單的分頁完成
上面功能中展示了數據的所有的頁碼,接下來我們將會對頁碼的展示進行升級,如:每頁展示十個頁碼
頁碼數量限制
url與html文件不變
views.py
users = [{"name": f"alex{i}", "pwd": "dsb"} for i in range(1, 301)] def page(request): user_list = users try: page = int(request.GET.get('page', 1)) if page <= 0: page = 1 except Exception: page = 1 """ 索引切片 page 起始 終止 1 0 10 2 10 20 3 20 30 """ # 每頁展示的數據 per_num = 10 # 數據切片起始值 start = (page - 1) * per_num # 數據切片終止值 end = page * per_num # 總數據條數 page_count = len(user_list) # 總頁碼數 sum_page, more = divmod(page_count, per_num) if more: sum_page += 1 # 前端循環的a標簽的值 num = [i for i in range(1, sum_page + 1)] # 頁碼限制 # 頁面最大顯示頁碼 max_show = 10 # 頁碼的切片的起始值 page_start = 0 # 頁碼切片的終止值 page_end = max_show # 頁碼的偏移量 half_page = max_show // 2 if page < max_show: """ 如果page在第一頁,什么都不做,即page_start=0,page_end=max_show """ pass if page > sum_page: """ 如果page參數大於總頁碼數,跳轉到最后一頁,針對於url上面手動輸入page參數 """ # 終止值為最后一頁 page_end = sum_page # 起始值向前便宜half_page page_start = page_end - half_page # 數據部分也需要設定,不然顯示為空 start = (sum_page - 1) * per_num end = sum_page * per_num else: """ page當前頁碼即不在第一頁,也不在最后一頁(或超過最后一頁),起始值向前偏移half_page,向后偏移half_page """ page_start = page - half_page page_end = page + half_page # 當總頁碼數小於每頁最大展示頁碼數量時,無論在那一頁都展示全部的頁碼(針對數據少,page處於max_show與sum_page之間時的bug) if sum_page < max_show: page_start = 0 page_end = sum_page num = num[page_start:page_end] user_list = user_list[start:end] return render(request, 'page.html', locals())
當前頁選中
bootstrap中active類選擇器是激活的樣式,在前端判斷后台接收到的page登不等於前端的頁碼,等於則添加激活樣式。
html文件
...... <div class="pull-left form-group col-sm-7"> <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for n in num %} <li class="{% if page == n %}active{% endif %}"><a href="{% url 'page' %}?page={{ n }}">{{ n }}</a> {# 主要操作在這里#} </li> {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </div> ......
正常情況下,激活樣式是完成的,但這里有個bug就是當手動在url地址中輸入大於總頁碼的page時就沒有激活樣式了,所以,我們需要在views文件中針對性的將page修改一下,如下:
...... if page > sum_page: """ 如果page參數大於總頁數,跳轉到最后一頁,針對於url上面手動輸入page參數 """ # 終止值為最后一頁 page_end = sum_page # 起始值向前便宜half_page page_start = page_end - half_page # 數據部分也需要設定,不然顯示為空 start = (sum_page - 1) * per_num end = sum_page * per_num # 當page大於總頁碼時,讓page等於最大的頁碼,為了給最后一頁添加激活樣式 # 主要操作在這里,原理是:因為當用戶手動輸入的頁碼大於總頁碼時,后台獲取的數據與前端的必然不同,因此,我們在這里手動將page設置為總頁碼,即可。 page = sum_page ......
效果如圖:
激活樣式添加完成
后台進行頁碼樣式的編寫及上下頁設置
這里主要在后台生成html代碼(頁碼相關的html代碼,包括樣式的激活,上下頁等,都在后台生成,前端只需要調用即可)
views.py

# -*- coding: utf-8 -*- # __author__ = "maple" users = [{"name": f"alex{i}", "pwd": "dsb"} for i in range(1, 301)] def page(request): user_list = users try: page = int(request.GET.get('page', 1)) if page <= 0: page = 1 except Exception: page = 1 """ 索引切片 page 起始 終止 0 10 10 20 20 30 """ # 每頁展示的數據 per_num = 3 # 數據切片起始值 start = (page - 1) * per_num # 數據切片終止值 end = page * per_num # 總數據條數 page_count = len(user_list) # 總頁碼數 sum_page, more = divmod(page_count, per_num) if more: sum_page += 1 # 前端循環的a標簽的值 num = [i for i in range(1, sum_page + 1)] # 頁碼限制 # 頁面最大顯示頁碼 max_show = 6 # 頁碼的切片的起始值 page_start = 0 # 頁碼切片的終止值 page_end = max_show # 頁碼的偏移量 half_page = max_show // 2 if page < max_show: """ 如果page在第一頁,什么都不做,即page_start=0,page_end=max_show """ pass if page > sum_page: """ 如果page參數大於總頁碼數,跳轉到最后一頁,針對於url上面手動輸入page參數 """ # 終止值為最后一頁 page_end = sum_page # 起始值向前偏移half_page page_start = page_end - half_page # 數據部分也需要設定,不然顯示為空 start = (sum_page - 1) * per_num end = sum_page * per_num # 當page大於總頁碼時,讓page等於最大的頁碼,為了給最后一頁添加激活樣式 page = sum_page else: """ page當前頁碼即不在第一頁,也不在最后一頁(或超過最后一頁),起始值向前偏移half_page,向后偏移half_page """ page_start = page - half_page page_end = page + half_page # 當總頁碼數小於每頁最大展示頁碼數量時,無論在那一頁都展示全部的頁碼(針對數據少,page處於max_show與sum_page之間時的bug) if sum_page < max_show: page_start = 0 page_end = sum_page num = num[page_start:page_end] html_list = [] # 頁碼樣式的頭 html_list.append( '<div class="pull-left form-group col-sm-7"><nav aria-label="Page navigation"><ul class="pagination">') # 當當前頁為1時,添加上一頁禁用樣式disabled if page == 1: html_list.append( '<li class="disabled"><a aria-label="Previous"><span aria-hidden="true">«</span></a></li>') else: html_list.append( '<li ><a href="?page={}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format( page - 1)) for n in num: if page == n: html_list.append('<li class="active"><a>{}</a></li>'.format(n)) else: html_list.append('<li><a href="?page={}">{}</a></li>'.format(n, n)) # 當前頁為最后一頁時,添加下一頁禁用樣式disabled if page == sum_page: html_list.append( '<li class="disabled"><a aria-label="Next"><span aria-hidden="true">»</span></a></li>') else: html_list.append( '<li><a href="?page={}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format( page + 1)) # 頁碼樣式的尾 html_list.append('</ul></nav></div>') # 將列表中的html代碼拼接起來 html_list = "".join(html_list) user_list = user_list[start:end] return render(request, 'page.html', locals())
html.py(附帶所有的關於關於頁碼的樣式)
{{ html_list|safe }}
小工具:跳轉
html頁面
{{ html_list|safe }} # form表單不寫method默認為get請求,且get請求會將input提交的值以url參數的形式保存並提交到后台 <form action=""> <input type="text" name="page"> <button>跳轉</button> </form>
至此,簡單的分頁功能就已經完成了,但我們以后開發項目必然要用到分頁功能,我們要如何使用自己開發的分頁功能呢?在寫一遍?不,我們將它封裝成類,在使用的時候進行調用即可。
封裝成類

class Pagination(object): def __init__(self, page, page_count, per_num=10, max_show=10): """ :param page:前端傳入的頁碼 :param page_count: 分頁的數據總條數 :param per_num: 每頁顯示的數據條數 :param max_show: 每頁顯示的最大頁碼數 """ self.page = page self.page_count = page_count self.per_num = per_num self.max_show = max_show try: self.page = int(self.page) if self.page <= 0: self.page = 1 except Exception: self.page = 1 """ 索引切片 page 起始 終止 0 10 10 20 20 30 """ # 數據切片起始值 self.start = (self.page - 1) * self.per_num # 數據切片終止值 self.end = self.page * self.per_num # 總頁碼數 self.sum_page, more = divmod(self.page_count, self.per_num) if more: self.sum_page += 1 # 前端循環的a標簽的值 self.num = [i for i in range(1, self.sum_page + 1)] # 頁碼限制 # 頁碼的切片的起始值 self.page_start = 0 # 頁碼切片的終止值 self.page_end = self.max_show # 頁碼的偏移量 half_page = self.max_show // 2 if self.page < self.max_show: """ 如果page在第一頁,什么都不做,即page_start=0,page_end=max_show """ pass if self.page > self.sum_page: """ 如果page參數大於總頁碼數,跳轉到最后一頁,針對於url上面手動輸入page參數 """ # 終止值為最后一頁 self.page_end = self.sum_page # 起始值向前偏移half_page self.page_start = self.page_end - half_page # 數據部分也需要設定,不然顯示為空 self.start = (self.sum_page - 1) * self.per_num self.end = self.sum_page * self.per_num # 當page大於總頁碼時,讓page等於最大的頁碼,為了給最后一頁添加激活樣式 self.page = self.sum_page else: """ page當前頁碼即不在第一頁,也不在最后一頁(或超過最后一頁),起始值向前偏移half_page,向后偏移half_page """ self.page_start = self.page - half_page self.page_end = self.page + half_page # 當總頁碼數小於每頁最大展示頁碼數量時,無論在那一頁都展示全部的頁碼 if self.max_show > self.sum_page: self.page_start = 0 self.page_end = self.sum_page # 當傳入的總數據量小於等於0時(主要是等於零),會報錯,通過下面的判斷來解決這個問題 if page_count <= 0: self.start = 0 self.end = 0 def page_html(self): num = self.num[self.page_start:self.page_end] html_list = [] # 頁碼樣式的頭 html_list.append( '<div class="pull-left form-group col-sm-7" style="padding-left:0"><nav aria-label="Page navigation"><ul class="pagination">') # 當前頁為1時,添加上一頁禁用樣式disabled if self.page == 1: html_list.append( '<li class="disabled"><a aria-label="Previous"><span aria-hidden="true">«</span></a></li>') else: html_list.append( '<li ><a href="?page={}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format( self.page - 1)) for n in num: if self.page == n: html_list.append('<li class="active"><a>{}</a></li>'.format(n)) else: html_list.append('<li><a href="?page={}">{}</a></li>'.format(n, n)) # 當前頁為最后一頁時,添加下一頁禁用樣式disabled if self.page == self.sum_page: html_list.append( '<li class="disabled"><a aria-label="Next"><span aria-hidden="true">»</span></a></li>') else: html_list.append( '<li><a href="?page={}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format( self.page + 1)) # 頁碼樣式的尾 html_list.append('</ul></nav></div>') # 將列表中的html代碼拼接起來 html_list = "".join(html_list) return html_list
使用自定義分頁器類
views.py
users = [{"name": f"alex{i}", "pwd": "dsb"} for i in range(1, 355)] from utils import pagination def page(request): user_list = users page = request.GET.get('page') pat_obj = pagination.Pagination(page, len(user_list)) # 實例化一個分頁器對象 user_list = user_list[pat_obj.start:pat_obj.end] # 進行數據的切片操作 return render(request, 'page.html', locals())
page.html
<div class="form-group col-sm-7"> <table class="table table-hover table-bordered"> <thead> <tr> <th>name</th> <th>pwd</th> </tr> </thead> <tbody> {% for user in user_list %} <tr> <td>{{ user.name }}</td> <td>{{ user.pwd }}</td> </tr> {% endfor %} </tbody> </table> </div> {{ pat_obj.page_html|safe }} {# 通過分頁器對象調用page_html方法 #}
注:分頁器中引入的是bootstrap框架的樣式,使用前需先在模板中引入bootstrap
分頁器終極版
分頁器:

# -*- coding: utf-8 -*- # __author__ = "maple" from django.http.request import QueryDict class Pagination(object): def __init__(self, page, page_count, qd=None, per_num=10, max_show=10): """ :param page:前端傳入的頁碼 :param page_count: 分頁的數據總條數 :param per_num: 每頁顯示的數據條數 :param max_show: 每頁顯示的最大頁碼數 """ self.page = page self.page_count = page_count self.per_num = per_num self.max_show = max_show self.qd = qd if not qd: qd = QueryDict(mutable=True) self.qd = qd try: self.page = int(self.page) if self.page <= 0: self.page = 1 except Exception: self.page = 1 """ 索引切片 page 起始 終止 1 0 10 2 10 20 3 20 30 """ # 數據切片起始值 self.start = (self.page - 1) * self.per_num # 數據切片終止值 self.end = self.page * self.per_num # 總頁碼數 self.sum_page, more = divmod(self.page_count, self.per_num) if more: self.sum_page += 1 # 前端循環的a標簽的值 self.num = [i for i in range(1, self.sum_page + 1)] # 頁碼限制 # 頁碼的切片的起始值 self.page_start = 0 # 頁碼切片的終止值 self.page_end = self.max_show # 頁碼的偏移量 half_page = self.max_show // 2 if self.page < self.max_show: """ 如果page在第一頁,什么都不做,即page_start=0,page_end=max_show """ pass if self.page > self.sum_page: """ 如果page參數大於總頁碼數,跳轉到最后一頁,針對於url上面手動輸入page參數 """ # 終止值為最后一頁 self.page_end = self.sum_page # 起始值向前偏移half_page self.page_start = self.page_end - half_page # 數據部分也需要設定,不然顯示為空 self.start = (self.sum_page - 1) * self.per_num self.end = self.sum_page * self.per_num # 當page大於總頁碼時,讓page等於最大的頁碼,為了給最后一頁添加激活樣式 self.page = self.sum_page else: """ page當前頁碼即不在第一頁,也不在最后一頁(或超過最后一頁),起始值向前偏移half_page,向后偏移half_page """ self.page_start = self.page - half_page self.page_end = self.page + half_page # 當總頁碼數小於每頁最大展示頁碼數量時,無論在那一頁都展示全部的頁碼 if self.max_show > self.sum_page: self.page_start = 0 self.page_end = self.sum_page # 當傳入的總數據量小於等於0時(主要是等於零),會報錯,通過下面的判斷來解決這個問題 if page_count <= 0: self.start = 0 self.end = 0 def page_html(self): num = self.num[self.page_start:self.page_end] html_list = [] # 頁碼樣式的頭 html_list.append( '<div class="pull-left form-group col-sm-7" style="padding-left:0"><nav aria-label="Page navigation"><ul class="pagination">') # 當前頁為1時,添加上一頁禁用樣式disabled if self.page == 1: self.qd['page'] = 1 html_list.append( '<li class="disabled"><a href="?{}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format( self.qd.urlencode())) else: self.qd['page'] = self.page -1 html_list.append( '<li ><a href="?{}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format( self.qd.urlencode())) for n in num: self.qd['page'] = n if self.page == n: html_list.append('<li class="active"><a>{}</a></li>'.format(n)) else: html_list.append('<li><a href="?{}">{}</a></li>'.format(self.qd.urlencode(), n)) # 當前頁為最后一頁時,添加下一頁禁用樣式disabled if self.page == self.sum_page: self.qd['page'] = self.sum_page html_list.append( '<li class="disabled"><a href="?{}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format( self.qd.urlencode())) else: self.qd['page'] = self.page + 1 html_list.append( '<li><a href="?{}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format( self.qd.urlencode())) # 頁碼樣式的尾 html_list.append('</ul></nav></div>') # 將列表中的html代碼拼接起來 html_list = "".join(html_list) return html_list
使用:
from utils import pagination # 導入自定義分頁器 page = request.GET.get('page', 1) #獲取當前頁碼參數 pag_obj = pagination.Pagination(page=page, page_count=customer_obj.count(),qd=request.GET.copy(), per_num=3, max_show=10) #實例化分頁器對象 customer_obj = customer_obj[pag_obj.start:pag_obj.end] # 對queryset對象進行分頁