django中的分頁器組件

django的組件-分頁器

引入分頁器

在博客園中,若是每一個人都發表一篇文章的話,若是我們不進行分頁的話,那麼博客園的首頁將會變得異常龐大,並且你永遠不知道你要拉到什麼何時才能拉到最底部,此時我們的分頁器就派上了用場,規定每一個html頁面只顯示多少篇文章,給咱們帶來了大大的便利。html

如下是博客園的分頁器:
python

此時我們須要作的就是這樣一個相似的分頁器。git

分頁器demo

建立數據庫模型

咱們首先作的就是數據庫的模型,在這裏給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

url控制器

須要給程序提供一個入口,當用戶輸入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),
]

views視圖函數

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。瀏覽器

templates模板

<!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 }}&nbsp;&nbsp;&nbsp;{{ book.price }}</li>
        {% endfor %}

    </ul>

</body>
</html>

此時我們將項目啓動起來,而後去瀏覽器查看:

此時的100條數據所有生成了,要記住的是:當數據批量插入後,須要將批量插入數據庫的語句給註釋掉。

爲何要用分頁器

咱們能夠查看到100條數據就已經這麼多了,可是數據不是一成不變的嗎,因此咱們須要使用分頁器。

導入分頁器

在視圖函數中導入分頁器須要用到這麼一句話:

from django.core.paginator import Paginator

此時咱們導入的是Paginator類,咱們須要實例化成對象,那麼這個對象就有本身的屬性和方法:

實例化Pagintor對象

須要在視圖函數中添加這麼一句話來實例化對象:

# 進行實例化
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 }}&nbsp;&nbsp;&nbsp;{{ 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 }}&nbsp;&nbsp;&nbsp;{{ book.price }}</li>
        {% endfor %}
    </ul>
</body>
</html>

沒跟上的同窗檢查下代碼。

分頁器優化1

大家真的覺得大功告成了嗎?固然是沒有的,舉個簡單的來講,若是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的時候,就沒有問題了:

那麼這個問題就解決了。

分頁器優化2

我們須要在瀏覽器本身輸入這個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設置動做;

有多少頁就設置多少個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:

爲點擊的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.若是都不符合,那麼就顯示在中間

那麼此時刷新瀏覽器就能看到:

第一種狀況:

第二種狀況:

第三種狀況:

那麼此時我們就完成了分頁器。

相關文章
相關標籤/搜索