目錄css
在博客園中,若是每一個人都發表一篇文章的話,若是我們不進行分頁的話,那麼博客園的首頁將會變得異常龐大,並且你永遠不知道你要拉到什麼何時才能拉到最底部,此時我們的分頁器就派上了用場,規定每一個html頁面只顯示多少篇文章,給咱們帶來了大大的便利。html
如下是博客園的分頁器:
python
此時我們須要作的就是這樣一個相似的分頁器。git
咱們首先作的就是數據庫的模型,在這裏給Book表定義了兩個字段,title和price:sql
from django.db import models # Create your models here. class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2)
而後咱們須要運行數據庫遷移命令:數據庫
python3 manage.py makemigrations python3 manage.py migrate
由於沒有對數據庫進行特殊設置,則默認使用的是sqlite數據庫,此時我們點擊pycharm查看新建立的數據庫:npm
此時表建立出來了,那麼數據從哪來呢?咱們確定是不可能手寫的,因此,咱們使用批量增長的方式將100條數據添加到數據庫中。django
須要給程序提供一個入口,當用戶輸入127.0.0.1:8000/index便進行駛入匹配,若是成功則進入到視圖函數中:bootstrap
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), ]
from django.shortcuts import render from .models import Book # Create your views here. def index(request): # 經過批量插入bulk_create的方式插入數據,這種方式是一條sql插入100條數據 book_list = [] for i in range(100): book = Book(title='boos_%s' % i, price=i*i) book_list.append(book) Book.objects.bulk_create(book_list) book_list = Book.objects.all() return render(request, 'index.html', locals())
此時我們就成功建立了視圖函數,那麼若是咱們想將全部的數據展現出來的話,我們須要一個index.html。瀏覽器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <ul> {% for book in book_list %} <li>{{ book.title }} {{ book.price }}</li> {% endfor %} </ul> </body> </html>
此時我們將項目啓動起來,而後去瀏覽器查看:
此時的100條數據所有生成了,要記住的是:當數據批量插入後,須要將批量插入數據庫的語句給註釋掉。
咱們能夠查看到100條數據就已經這麼多了,可是數據不是一成不變的嗎,因此咱們須要使用分頁器。
在視圖函數中導入分頁器須要用到這麼一句話:
from django.core.paginator import Paginator
此時咱們導入的是Paginator類,咱們須要實例化成對象,那麼這個對象就有本身的屬性和方法:
須要在視圖函數中添加這麼一句話來實例化對象:
# 進行實例化 paginator = Paginator(book_list, 10)
這句話的意思就是對book_list進行分頁,每頁顯示10條數據。
那麼咱們說過,實例化的對象有本身的屬性和方法,這裏有三個屬性,分別是:count、num_pages、page_range
# 實例化的方法和屬性 print('總數:', paginator.count) print('總頁數:', paginator.num_pages) print('頁碼的列表:', paginator.page_range)
此時讓咱們從新發送一個請求,而後再pycharm中查看打印結果:
此時就已經獲取到了總數、總頁數了,此時咱們就能夠進行下一步操做了。
這個咱們可想而知,確定是1頁10條數據,那麼咱們此時就須要獲得這個頁碼:
# 獲取當前頁碼 current_page_num = int(request.GET.get('page', 1))
request.GET.get('page')
獲取當前的頁碼,1表明的是默認顯示第一頁。
那麼咱們只是拿到了這個頁碼,這個數據從哪裏拿呢?確定是從分頁器對象裏面拿了:
# 根據頁碼拿到數據 current_page = paginator.page(current_page_num)
此時,這個current_page
就是某一頁的數據,而後咱們須要在模板中更新語法成:
<ul> {% for book in current_page %} <li>{{ book.title }} {{ book.price }}</li> {% endfor %} </ul>
此時大功告成,咱們刷新瀏覽器就能看到結果了。
若是咱們想訪問第二頁的數據,那麼咱們須要在瀏覽器輸入http://127.0.0.1:8001/index/?page=2
就能訪問第二頁的數據:
此時我們就大功告成了,展現下源代碼:
# views.py from django.shortcuts import render from .models import Book from django.core.paginator import Paginator # Create your views here. def index(request): ''' # 經過批量插入bulk_create的方式插入數據,這種方式是一條sql插入100條數據 book_list = [] for i in range(100): book = Book(title='boos_%s' % i, price=i*i) book_list.append(book) Book.objects.bulk_create(book_list) ''' book_list = Book.objects.all() # 進行實例化 paginator = Paginator(book_list, 10) # 實例化的方法和屬性 print('總數:', paginator.count) print('總頁數:', paginator.num_pages) print('頁碼的列表:', paginator.page_range) # print(request.GET.get('page')) current_page_num = int(request.GET.get('page', 1)) current_page = paginator.page(current_page_num) return render(request, 'index.html', locals())
# urls.py from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), ]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <ul> {% for book in current_page %} <li>{{ book.title }} {{ book.price }}</li> {% endfor %} </ul> </body> </html>
沒跟上的同窗檢查下代碼。
大家真的覺得大功告成了嗎?固然是沒有的,舉個簡單的來講,若是page=-1的話,或者超過了最大頁數的話,會怎麼樣?
報錯了,既然報錯了我們就須要捕獲異常,由於咱們輸入的是-1或者10以上都會報錯,那麼不如讓都跳轉到第一頁去:
# 異常捕獲 try: current_page_num = int(request.GET.get('page', 1)) current_page = paginator.page(current_page_num) except Exception as e: current_page = paginator.page(1)
那麼當咱們再次輸入-1的時候,就沒有問題了:
那麼這個問題就解決了。
我們須要在瀏覽器本身輸入這個page是否是特別麻煩,因此,咱們須要利用bootstrap來實現點擊跳轉,具體的就是引入bootstrap的分頁器。
咱們須要在index.html中添加bootstrap分頁器組件:
# 添加bootstrap分頁器組件 <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">上一頁</span> </a> </li> <li><a href="#">1</a></li> <li><a href="#">2</a></li> <li><a href="#">3</a></li> <li><a href="#">4</a></li> <li><a href="#">5</a></li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">下一頁</span> </a> </li> </ul> </nav>
那麼這個時候我們再去瀏覽器刷新的時候,就能夠看到效果,固然,這些標籤點擊了也是沒有任何做用的:
接下來我們須要對每一個li設置動做;
由於我們直接引用的bootstrap組件就只有5個,因此咱們有多少頁就須要設置多少給li標籤:
# {% for item in paginator.page_range %} <li><a href="?page={{ item }}">{{ item }}</a></li> {% endfor %}
首先這個paginator是一個分頁器對象,而後呢page_range表示的頁碼的列表,那麼咱們對這個進行循環的話,就能夠作到有多少頁就設置多少個li標籤了。
這裏是瀏覽器刷新後的效果:
而後當咱們點擊這1-10就能夠實現跳轉了:
如今呢是完成了這個標籤的,可是咱們發現沒有,你點擊了5而後跳轉到了第5頁,你從請求url中看到了這是第5頁,可是這個li標籤卻看不出來,因此咱們還須要將點擊的Li標籤加一個class:
我們在views視圖中獲取到了每一頁的頁碼current_page_num
,而後咱們在模板中也拿到了頁碼item
,那麼咱們若是讓這兩個值相同的話,就給它加一個樣式:
{% for item in paginator.page_range %} {% if current_page_num == item %} <li class="active"><a href="?page={{ item }}">{{ item }}</a></li> {% else %} <li><a href="?page={{ item }}">{{ item }}</a></li> {% endif %} {% endfor %}
下面是瀏覽器上看到的效果
由於我們的上一頁和下一頁是沒有進行設置的,因此點擊是沒有進行任何跳轉的。
首先解決我們的下一頁,思路是這樣的:好比咱們如今在第9頁上,對第九頁進行判斷,若是存在下一頁那就跳轉到下一頁去,若是沒有,那麼這個li標籤就不能跳轉,即給他禁止:
# 下一頁 {% if current_page.has_next %} <li> <a href="?page={{ current_page.next_page_number }}" aria-label="Next"> <span aria-hidden="true">下一頁</span> </a> </li> {% else %} <li class='disabled'> <a href="#" aria-label="Next"> <span aria-hidden="true">下一頁</span> </a> </li> {% endif %}
看一下效果圖:
那麼同理,上一頁也是這樣作到的:
# 上一頁 {% if current_page.has_previous %} <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">上一頁</span> </a> </li> {% else %} <li class="disabled"> <a href="#" aria-label="Previous"> <span aria-hidden="true">上一頁</span> </a> </li> {% endif %}
當到了第一頁的時候,就不能點擊上一頁了。
首先讓咱們看一下現象
若是領導吩咐每一頁只顯示5行數據的話,那麼就會有20頁,那麼若是一頁就顯示2條數據的話呢?因此這些確定是不合理的,我們須要根據這個頁碼進行修改:
current_page_num = int(request.GET.get('page', 1)) # 顯示第一頁的頁碼 if paginator.num_pages > 11: # 若是總頁數大於19,就進入到這個判斷中 if current_page_num-5 < 1: # 若是當前所在的頁數減去5頁小於1 page_range = range(1, 11) # 那麼頁碼的範圍就是1-11 elif current_page_num+5 > paginator.num_pages: # 若是當前頁數+5大於總頁數 page_range = range(paginator.num_pages-11, paginator.num_pages+1) # 那麼此時頁碼的範圍就是總頁數減去11到總頁碼+1 else: page_range = page_range = range(current_page_num-5, current_page_num+5) # 其他狀況就顯示在中間 else: page_range = paginator.page_range
當我們的請求發過去,只有兩種狀況:
1.總頁數大於11
2.總頁數小於11
若是小於11的話,那麼就走下面的else,若是頁數大於11,那麼就走上面的條件判斷,此時的條件判斷分爲三種狀況(由於咱們想讓這個頁碼一直顯示在中間):
1.若是當前頁碼減去5頁的話小於1頁,那麼此時頁碼的範圍就是1-11
2.若是當前頁碼加上5頁大於總頁數的話,那麼此時的頁碼範圍就是當前頁數減去11頁到當前頁數加上1頁之間,左合右開
3.若是都不符合,那麼就顯示在中間
那麼此時刷新瀏覽器就能看到:
第一種狀況:
第二種狀況:
第三種狀況:
那麼此時我們就完成了分頁器。