Django擴充套件 分頁元件
阿新 • • 發佈:2020-07-16
我們在展示資訊過程中,如果資訊量過多,會給人非常的不友好,這個時候需要通過分頁使得介面更簡潔友好
Django 基於GET請求的分頁功能
假設 每一個 顯示十條資料 可得到以下公式
頁碼 | 起始 | 結束 |
---|---|---|
1 | 0 | 10 |
2 | 10 | 20 |
3 | 20 | 30 |
... | ... | ... |
... | (page-1)*5 | page*10 |
我們用程式碼實現一下吧
page_num = int(request.GET.get("page")) # 獲取頁碼數 per_page_num = 10 # 每頁顯示條數 # 通過條件對查詢到的資料進行切片處理 customers_obj = models.Customer.objects.all()[ (page_num-1)*per_page_num:page_num*per_page_num ]
我們需要在前端生成分頁按鈕
分析
- 需要獲取每頁顯示的數量
- 需要獲取頁碼生成的數量
- 前端進行迴圈生成
頁碼生成的數量 = 資料總數 / 每頁顯示的數量
def customers(request): page_num = int(request.GET.get("page")) per_page_num = 10 # 每頁顯示條數 customers_count = models.Customer.objects.all().count() # 獲取總資料數量 shanum, yunum = divmod(customers_count, per_page_num) #計算商數和餘數 # 生成要展示的頁碼數 if yunum: page_num_count = shanum + 1 else: page_num_count = shanum # 根據每頁顯示的條數對查出來的資料進行切割 customers_obj = models.Customer.objects.all()[ (page_num-1)*per_page_num:page_num*per_page_num ] return render( request,"saleshtml\\customers.html", { "customers_obj": customers_obj, "page_num_count": range(1, page_num_count+1) # 展示頁碼沒有第一頁 } )
<nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for i in page_num_range %} <li><a href="/customers/?page={{i}}">{{i}}</a></li> {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav>
- 生成頁面樣式不友好 如果上百頁 就一堆頁碼條
對頁碼生成邏輯進行改進
所在頁碼 | 欄位1 | 欄位2 | 欄位3 | 欄位4 | 欄位5 |
---|---|---|---|---|---|
3 | 1 | 2 | 3 | 4 | 5 |
4 | 2 | 3 | 4 | 5 | 6 |
5 | 3 | 4 | 5 | 6 | 7 |
6 | 4 | 5 | 6 | 7 | 8 |
分析
- 欄位三兩邊的數量: 分頁按鈕的條數 整除 2
- 分頁按鈕起始: 當前頁碼 - 欄位三兩邊的數量
- 分頁按鈕結束: 當前頁碼 + 欄位三兩邊的數量
def customers(request): try: page_num = int(request.GET.get("page")) except Exception: page_num = 1 per_page_num = 10 # 每頁顯示條數 customers_count = models.Customer.objects.all().count() # 獲取總資料數量 shanum, yunum = divmod(customers_count, per_page_num) # 計算商數和餘數 # 生成要展示的頁碼數 if yunum: page_num_count = shanum + 1 else: page_num_count = shanum # 如果頁碼數小於等於零 或者大於總頁碼數 讓他不出問題 if page_num <= 0: page_num = 1 elif page_num > page_num_count: page_num = page_num_count # 根據每頁顯示的條數對查出來的資料進行切割 customers_obj = models.Customer.objects.all()[ (page_num-1)*per_page_num:page_num*per_page_num ] page_num_show = 5 # 分頁按鈕生成的數量 half_show = page_num_show//2 # 分頁按鈕中心兩端的數量 start_page_num = page_num - half_show # 開始位置 end_page_num = page_num + half_show +1 # 結束位置 page_num_range = range(start_page_num, end_page_num) return render( request, "saleshtml\\customers.html", { "customers_obj": customers_obj, "page_num_range": page_num_range, } )
問題:
解決:
- 頁碼數由後臺生成
start_page_num = page_num - half_show # 開始位置 end_page_num = page_num + half_show +1 # 結束位置
- 解決問題
def customers(request): try: page_num = int(request.GET.get("page")) except Exception: page_num = 1 per_page_num = 10 # 每頁顯示條數 customers_count = models.Customer.objects.all().count() # 獲取總資料數量 shanum, yunum = divmod(customers_count, per_page_num) # 計算商數和餘數 # 生成要展示的頁碼數 if yunum: page_num_count = shanum + 1 else: page_num_count = shanum # 如果頁碼數小於等於零 或者大於總頁碼數 讓他不出問題 if page_num <= 0: page_num = 1 elif page_num > page_num_count: page_num = page_num_count # 根據每頁顯示的條數對查出來的資料進行切割 customers_obj = models.Customer.objects.all()[ (page_num-1)*per_page_num:page_num*per_page_num ] page_num_show = 5 # 分頁按鈕生成的數量 half_show = page_num_show//2 # 分頁按鈕中心兩端的數量 if page_num - half_show <= 0: start_page_num = 1 end_page_num = page_num_show + 1 elif page_num + half_show > page_num_count: start_page_num = page_num_count - page_num_show + 1 end_page_num = page_num_count + 1 else: start_page_num = page_num - half_show # 開始位置 end_page_num = page_num + half_show +1 # 結束位置 page_num_range = range(start_page_num, end_page_num) return render( request, "saleshtml\\customers.html", { "customers_obj": customers_obj, "page_num_range": page_num_range, } )
對分頁功能進行封裝
封裝到後臺
def customers(request): try: page_num = int(request.GET.get("page")) except Exception: page_num = 1 per_page_num = 10 # 每頁顯示條數 customers_count = models.Customer.objects.all().count() # 獲取總資料數量 shanum, yunum = divmod(customers_count, per_page_num) # 計算商數和餘數 # 生成要展示的頁碼數 if yunum: page_num_count = shanum + 1 else: page_num_count = shanum # 如果頁碼數小於等於零 或者大於總頁碼數 讓他不出問題 if page_num <= 0: page_num = 1 elif page_num > page_num_count: page_num = page_num_count # 根據每頁顯示的條數對查出來的資料進行切割 customers_obj = models.Customer.objects.all()[ (page_num-1)*per_page_num:page_num*per_page_num ] page_num_show = 5 # 分頁按鈕生成的數量 half_show = page_num_show//2 # 分頁按鈕中心兩端的數量 if page_num - half_show <= 0: start_page_num = 1 end_page_num = page_num_show + 1 elif page_num + half_show > page_num_count: start_page_num = page_num_count - page_num_show + 1 end_page_num = page_num_count + 1 else: start_page_num = page_num - half_show # 開始位置 end_page_num = page_num + half_show +1 # 結束位置 page_num_range = range(start_page_num, end_page_num) page_html = '' # 開頭標籤樣式之類 page_per_html = ''' <nav aria-label="Page navigation"> <ul class="pagination">''' page_html += page_per_html # 上一頁 if page_num > 1: per_page = f''' <li><a href="/customers/?page={page_num-1}" aria-label="Previous"> <span aria-hidden="true">«</span></a></li>''' page_html += per_page # 迴圈新增按鈕 for page in page_num_range: page_num_html = f''' <li><a href="/customers/?page={page}">{page}</a></li> ''' page_html += page_num_html # 下一頁 if page_num < page_num_count: next_page = f''' <li><a href="/customers/?page={page_num+1}" aria-label="Next"> <span aria-hidden="true">»</span> </a></li> ''' page_html += next_page # 標籤樣式收尾 page_next_html = '''</ul></nav>''' page_html += page_next_html return render( request, "saleshtml\\customers.html", {"customers_obj": customers_obj, "page_html": page_html,})
<!--前端通過safe使字串變成可用標籤--> {{ page_html|safe }}
將分頁功能封裝成元件
# mark_safe 將後端生成的字串標記為HTML 前端直接使用 就不用再 {{xxx|salf}} from django.utils.safestring import mark_safe class MyPageNation(): def __init__(self, page_num, total_count, per_page_num, page_num_show, base_url): self.per_page_num = per_page_num # 每頁顯示資料條數 self.page_num_show = page_num_show # 分頁按鈕生成的數量 self.base_url = base_url # 分頁元件中的URL self.total_count = total_count # 資料的總量 try: page_num = int(page_num) except Exception: page_num = 1 self.page_num = page_num # 請求的page shanum, yunum = divmod(self.total_count, self.per_page_num) # 計算商數和餘數 # 生成要展示的頁碼數 if yunum: self.page_num_count = shanum + 1 else: self.page_num_count = shanum # 如果頁碼數小於等於零 或者大於總頁碼數 讓他不出問題 if self.page_num <= 0: self.page_num = 1 elif page_num > self.page_num_count: self.page_num = self.page_num_count half_show = self.page_num_show//2 # 分頁按鈕中心兩端的數量 if page_num - half_show <= 0: start_page_num = 1 end_page_num = self.page_num_show + 1 elif page_num + half_show > self.page_num_count: start_page_num = self.page_num_count - self.page_num_show + 1 end_page_num = self.page_num_count + 1 else: start_page_num = page_num - half_show end_page_num = page_num + half_show + 1 self.start_page_num = start_page_num # 開始位置 self.end_page_num = end_page_num # 結束位置 @property def start_data_num(self): return (self.page_num-1)*self.per_page_num @property def end_data_num(self): return self.page_num*self.per_page_num def page_html(self): page_num_range = range(self.start_page_num, self.end_page_num) page_html = '' # 開頭標籤樣式之類 page_per_html = ''' <nav aria-label="Page navigation"> <ul class="pagination">''' page_html += page_per_html # 上一頁 if self.page_num > 1: per_page = f''' <li><a href="{self.base_url}?page={self.page_num-1}" aria-label="Previous"> <span aria-hidden="true">«</span></a></li>''' page_html += per_page # 迴圈新增按鈕 for page in page_num_range: if self.page_num == page: page_num_html = f''' <li class="active"><a href="{self.base_url}?page={page}">{page}</a></li> ''' else: page_num_html = f''' <li><a href="{self.base_url}?page={page}">{page}</a></li> ''' page_html += page_num_html # 下一頁 if self.page_num < self.page_num_count: next_page = f''' <li><a href="{self.base_url}?page={self.page_num+1}" aria-label="Next"> <span aria-hidden="true">»</span> </a></li> ''' page_html += next_page # 標籤樣式收尾 page_next_html = '''</ul></nav>''' page_html += page_next_html return mark_safe(page_html) # 將最後生成的html標籤返回給前端