Django搭建個人博客:文章分頁

隨着時間的推移(加上勤奮的寫作!),你的博客文章一定會越來越多。如果不進行處理,可能同一個頁面會擠上成百上千的文章,不美觀不說,還降低了頁面的反應速度。

這個時候就需要對文章進行分頁的處理。

利用輪子

寫一個完善的分頁功能是有些難度的,好在Django已經幫你準備好一個現成的分頁模塊了(Django把大部分基礎功能都替你準備好了!)。內置模塊雖然簡單,但是對博客來說完全足夠了。

我們要用到的是Paginator類。在Shell中可以充分嘗試它的用法:

>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)

>>> p.count
4
>>> p.num_pages
2
>>> p.page_range
range(1, 3)

>>> page1 = p.page(1)
>>> page1
<Page 1 of 2>
>>> page1.object_list
['john', 'paul']

>>> page2 = p.page(2)
>>> page2.object_list
['george', 'ringo']
>>> page2.has_next()
False
>>> page2.has_previous()
True
>>> page2.has_other_pages()
True
>>> page2.previous_page_number()
1

這是一個官網的例子。詳見:Pagination

有了這個類,剩下的工作就是把它應用到項目中去。

輕車熟路

要對文章列表分頁,因此就要修改article/views.pydef article_list()視圖:

article/views.py

...
# 引入分頁模塊
from django.core.paginator import Paginator

def article_list(request):
    # 修改變量名稱(articles -> article_list)
    article_list = ArticlePost.objects.all()

    # 每頁顯示 1 篇文章
    paginator = Paginator(article_list, 1)
    # 獲取 url 中的頁碼
    page = request.GET.get('page')
    # 將導航對象相應的頁碼內容返回給 articles
    articles = paginator.get_page(page)

    context = { 'articles': articles }
    return render(request, 'article/list.html', context)

...

在視圖中通過Paginator類,給傳遞給模板的內容做了手腳:返回的不再是所有文章的集合,而是對應頁碼的部分文章的對象,並且這個對象還包含了分頁的方法。

我們在前面的文章已經接觸過一些將參數傳遞到視圖的手段了:

  • 通過POST請求將表單數據傳遞到視圖
  • 通過url將地址中的參數傳遞到視圖

這裏用到了另一種方法:在GET請求中,在url的末尾附上?key=value的鍵值對,視圖中就可以通過request.GET.get('key')來查詢value的值。

然後改寫模板,在最末尾的</div>前面,加入分頁的內容:

templates/article/list.html

...

<!-- 頁碼導航 -->
<div class="pagination row">
    <div class="m-auto">
        <span class="step-links">
            <!-- 如果不是第一頁,則顯示上翻按鈕 -->
            {% if articles.has_previous %}
                <a href="?page=1" class="btn btn-success">
                    &laquo; 1
                </a>
                <span>...</span>
                <a href="?page={{ articles.previous_page_number }}" 
                   class="btn btn-secondary"
                >
                    {{ articles.previous_page_number }}
                </a>
            {% endif %}

            <!-- 當前頁面 -->
            <span class="current btn btn-danger btn-lg">
                {{ articles.number }}
            </span>

            <!-- 如果不是最末頁,則顯示下翻按鈕 -->
            {% if articles.has_next %}
                <a href="?page={{ articles.next_page_number }}"
                   class="btn btn-secondary"
                >
                    {{ articles.next_page_number }}
                </a>
                <span>...</span>
                <a href="?page={{ articles.paginator.num_pages }}"
                   class="btn btn-success"
                >
                    {{ articles.paginator.num_pages }} &raquo;
                </a>
            {% endif %}
        </span>
    </div>
</div>

...

內容也比較簡單,用到了前面的Shell中演示的部分方法,判斷當前頁所處的位置。

這樣就行了!補充幾篇文章(筆者共6篇),方便測試。刷新頁面後是這樣的:

視圖中設置了每頁只有1篇文章,所以就真的只有1篇了。

當然這只是爲了測試,實際環境中肯定要遠大於1篇的。

點擊第2頁的按鈕後是這樣的:

看到頂部地址欄中的變化了嗎?

思考一下page是如何從模板傳遞到視圖的。

總結

除模板外,我們只寫了4行代碼,就有了還不錯的分頁導航,Django就是這麼貼心。

除了對文章列表,你可以對任何你想分頁的地方運用此模塊(比如以後要講到的評論),滿足用戶各類的需求。

讀者還可以稍加閱讀Bootstrap 4官方文檔,改寫一個符合自己品味的外觀。


轉載請並註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章