分頁是每個項目必不可少要寫的一個功能,該篇文章就將記錄一下使用ORM寫分頁的過程。
假設我們的數據庫里面需要顯示一些數據,而這個表中的數據大約有幾千條數據,那么我們不可能將所有的數據都顯示出來,那么就需要使用分頁來顯示一部分數據,使用頁數來進行翻頁。在下面這個過程,我以一個demo的形式進行敘述。
1.要想有許多數據,就要先創建一個存儲數據的表,下面就使用模型類創建一個表。
class TeacherTest(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max_length=20)
可以看到,這個表創建成功后有兩個字段,第一個字段是id,第二個字段是name。
2.分頁可以說分為兩大部分,第一部分就是考慮顯示部分數據在界面上,第二部分就是考慮頁碼如何寫。如果想象不出是什么樣子,可以參考一下博客園的分頁,如下圖:
首先考慮第一部分:如何顯示部分數據在前端上,而不是顯示表中所有的數據。這種情況下,我們會考慮使用切片的知識,比如:字符串str1="abcdefg"想要獲取到abc怎么辦呢,就使用切片,str2=str1[0:3]這樣,就可以獲取到了abc這個字符串。同樣我們可以查詢出所有的數據,然后通過切片的方法只獲取到第幾條到第幾條數據,這樣的話就可以顯示出部分的數據了。
我們定義一下,每頁顯示5條數據,那么使用orm顯示第一頁的數據就應該是:TeacherTest.objects.all()[0:5]。根據這個規律展開以下分析:
顯示數據 頁數 切片 切片分析
第1條-第5條數據 1 [0:5] [(1-1)*5:1*5]
第6條-第10條數據 2 [5:10] [(2-1)*5:2*5]
第11條-第15條數據 3 [10:15] [(3-1)*5:3*5]
......
第m條-第n條數據 j [m-1:n] [(j-1)*5:j*5]
通過上面的分析,我們知道了頁數與顯示數據的切片的關系了,那么我們就可以解決了一個顯示的問題。
orm顯示數據的語句就是:TeacherTest.objects.all()[(頁碼-1)*5:頁碼*5]
點擊頁碼按鈕通過url傳遞參數,后端獲取傳遞的頁碼數就可以顯示對應的數據了。
3.通過上面分析已經解決了顯示問題,那么接下來就要顯示分頁了。要想知道分頁,首先要知道的就是有多少條數據,然后根據計算這些數據需要多少頁來顯示數據。
獲取總數據量:TeacherTest.objects.count()
假設表中的數據量是26條數據,那么可以分6頁,最后一頁顯示1條數據;數據量是27條,也是分6頁,最后一頁顯示2條數據。所有我們可以先計算出每頁顯示5條數據的頁數,然后再計算是否還有不足5條數據,如果還有不足5條數據需要顯示,那么就再計算出每頁顯示5條數據的頁數加上1頁,就得出總頁數了。
偽代碼如下:
data_count=Teacher.objects.count() # 滿足每頁5條數據的頁數 page_five=data_count//5 # 計算是否有余數 page=data_count%5 if page==0: # 總頁數 page_num=page_five else: # 總頁數 page_num=page_five+1
也可以使用divmod(a,b)函數來計算頁數,如果不了解這個內置函數的話,可以通過網上查詢來獲悉這個函數的用法。
最后我們計算出了頁碼總數,就需要在前端顯示分頁的頁碼,通過我們點擊給前端傳遞參數。如果將頁數傳遞到前端的話,前端沒有range可以讓我們使用來遍歷,顯示每個頁碼,我們只能在后端做好后,將頁碼傳遞到前端。這里我使用的是html在后端拼接,然后傳遞到前端。下面可以參考具體的代碼來學習:
后端代碼:
def show_page(request): if request.method=="GET": current_page=request.GET.get("page") # 獲取跳轉的頁數 current_page=int(current_page) show_num=5 # 顯示條數 """ 1-5條 [0:5] 1 [(1-1)*5:1*5] 6-10條 [5:10] 2 [(2-1)*5:2*5] 11-15條[10:15] 3 [(3-1)*5:3*5] m-n條 [m-1:n] h [(m-1)*5:n*5] """ start_data=(current_page-1)*show_num # 從第幾條數據顯示 end_data=current_page*show_num # 顯示到第幾條技術 """ 顯示頁數 """ data_count=models.TeacherTest.objects.count() # 數據的總數量 m,n=divmod(data_count,show_num) page_list=[] if n==0: page_count=m for p in range(1,page_count+1): page='<li><a href="/app05/page/?page={0}">{0}</a></li>'.format(p) page_list.append(page) else: page_count=m+1 for p in range(1,page_count+1): page = '<li><a href="/app05/page/?page={0}">{0}</a></li>'.format(p) page_list.append(page) show_data=models.TeacherTest.objects.all()[start_data:end_data] return render(request,"page.html",{"allteacher":show_data,"pagecount":page_count,"page_list":page_list})
前端代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- Optional theme --> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> </head> <body> <table class="table-bordered" border="1" width="300"> {% for teacher in allteacher %} <tr> <td>{{ teacher.id }}</td> <td>{{ teacher.name }}</td> </tr> {% endfor %} </table> <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for page in page_list %} {{ page|safe }} {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </body> </html>
==============================================================================================================
此時分頁就基本上寫完了,但是我們在使用的時候會發現一個問題,就是如果有300條數據的時候,頁數就會有60頁,此時分頁的頁碼就會全部顯示到界面上,那樣的話就顯示不好看了。所以就要顯示分頁的長度了。
以下代碼就是更新后的代碼
def show_page(request): if request.method=="GET": current_page=request.GET.get("page") # 獲取跳轉的頁數 current_page=int(current_page) show_num=5 # 顯示條數 """ 1-5條 [0:5] 1 [(1-1)*5:1*5] 6-10條 [5:10] 2 [(2-1)*5:2*5] 11-15條[10:15] 3 [(3-1)*5:3*5] m-n條 [m-1:n] h [(m-1)*5:n*5] """ start_data=(current_page-1)*show_num # 從第幾條數據顯示 end_data=current_page*show_num # 顯示到第幾條技術 """ 顯示頁數 """ data_count=models.TeacherTest.objects.count() # 數據的總數量 page_count,n=divmod(data_count,show_num) if n: page_count+=1 # 總共展示11頁 max_page=5 half_max_page=max_page//2 # 頁面上展示的頁碼從哪開始 page_start=current_page-half_max_page # 頁面上展示的頁碼到哪結束 page_end=current_page+half_max_page # 如果當前頁加上一半比總頁碼數還大 if page_end>page_count: page_end=page_count page_start=page_count-max_page # 如果當前頁減去一半,比1還小 if page_start<=1: page_start=1 page_end=max_page page_list=[] for p in range(page_start,page_end+1): page='<li><a href="/app05/page/?page={0}">{0}</a></li>'.format(p) page_list.append(page) show_data=models.TeacherTest.objects.all()[start_data:end_data] return render(request,"page.html",{"allteacher":show_data,"pagecount":page_count,"page_list":page_list})