穩定易用的 Django 分頁庫,完善分頁功能


作者:HelloGitHub-追夢人物

文中所涉及的示例代碼,已同步更新到 HelloGitHub-Team 倉庫

通過 Django Pagination 實現簡單分頁 中,我們實現了一個簡單的分頁導航。但效果有點差強人意,我們只能點上一頁和下一頁的按鈕進行翻頁。比較完善的分頁效果應該像下面這樣,但想實現這樣一種效果,Django Pagination 內置的 API 已無能為力。接下來我們將通過拓展 Django Pagination 來實現下圖這樣比較完善的分頁效果。

分頁效果概述

一個比較完善的分頁效果應該具有以下特性,就像上圖展示的那樣,很多網站都采用了類似這種的分頁導航方式。

  • 始終顯示第一頁和最后一頁。
  • 當前頁碼高亮顯示。
  • 顯示當前頁碼前后幾個連續的頁碼。
  • 如果兩個頁碼號間還有其它頁碼,中間顯示省略號以提示用戶。

分頁思路

如果需要自己來實現分頁效果,我們會怎么做呢?先來分析一下導航條的組成部分,可以看到整個分頁導航條其實可以分成 7 個部分:

  1. 第 1 頁頁碼,這一頁需要始終顯示。
  2. 第 1 頁頁碼后面的省略號部分。但要注意如果第 1 頁的頁碼號后面緊跟着頁碼號 2,那么省略號就不應該顯示。
  3. 當前頁碼的左邊部分,比如這里的 3-4。
  4. 當前頁碼,比如這里的 5。
  5. 當前頁碼的右邊部分,比如這里的 6-7。
  6. 最后一頁頁碼前面的省略號部分。但要注意如果最后一頁的頁碼號前面跟着的頁碼號是連續的,那么省略號就不應該顯示。
  7. 最后一頁的頁碼號。

因此我們的思路是,在視圖中依據上述規則生成頁碼列表,然后在模板中循環顯示頁碼列表就可以了。有了思路,實現起來其實也並不很難。不過對於這類常見需求,別人早就幫我們實現好了,本着不重復造輪子的原則,直接拿來用就好。

第一個 Django 第三方拓展:django-pure-pagination

我們第一次開始接觸 django 第三方拓展,在此之前我們一直都基於 django 本身我們提供的功能在開發,然而 django 強大的地方就在於海量的第三方應用供我們挑選,幾乎大部分 web 開發中的需求,django 都能找到他人已經寫好的第三方應用,拿來即用。

事實上,正確的 django 開發姿勢應該是這樣的:

  1. 充分理解你的需求,想一想,如果自己實現,我會怎么做?
  2. 通過 Google、GitHub、開發者社區論壇等調研已有的實現類似需求的應用
  3. 拿來即用,並嘗試理解他人是如何實現這個功能的

以我們的分頁功能舉例:

首先我們上面分析了分頁需求的實現。然后我在 GitHub 上通過 django pagination 關鍵詞進行搜索,在比較了多個 star 數比較高的項目后,發現 django-pure-pagination 文檔最清晰,使用最簡單,因此決定將這個應用集成到我們的博客來。值得一提的是,盡管這個應用顯示作者最后一次更新代碼在 4 年前,但我粗略瀏覽了一下源碼,發現其依賴的 django api 4 年來異常穩定,所以確保能在 django 2.2 中使用。

接下來我們就來使用它,首先安裝它:

$ pipenv install django-pure-pagination

然后將它注冊到 INSTALLED_APPS 里:

INSTALLED_APPS = [
	# ...
    'pure_pagination',  # 分頁

    'blog.apps.BlogConfig',  # 注冊 blog 應用
    'comments.apps.CommentsConfig',  # 注冊 comments 應用
]

修改一下 IndexView,讓它繼承 django-pure-pagination 提供的 PaginationMixin,這個混入類將為我們提供上述提到的分頁功能。

class IndexView(PaginationMixin, ListView):
    model = Post
    template_name = 'blog/index.html'
    context_object_name = 'post_list'
    paginate_by = 10

然后我們可以在 common.py 配置中配置一下分頁的效果,這是 django-pure-pagination 提供的配置項,用於個性化配置分頁效果:

# django-pure-pagination 分頁設置
PAGINATION_SETTINGS = {
    'PAGE_RANGE_DISPLAYED': 4, # 分頁條當前頁前后應該顯示的總頁數(兩邊均勻分布,因此要設置為偶數),
    'MARGIN_PAGES_DISPLAYED': 2, # 分頁條開頭和結尾顯示的頁數
    'SHOW_FIRST_PAGE_WHEN_INVALID': True, # 當請求了不存在頁,顯示第一頁
}

在模板中需要分頁的地方,調用分頁對象的 render 方法就可以了,比如在 index.html 中:

{% if is_paginated %}
	{{ page_obj.render }}
{% endif %}

注意這里 page_obj 是分頁后的對象列表,具體請參考上一篇文章的講解。render 方法會自動幫我們渲染一個預先定義好的分頁條,至此,分頁功能就完成了。

自定義模板

有時候預定義的分頁條並不能滿足我們的需求,我們可以通過自定義的模板來覆蓋預定義的模板。django 查找模板的順序是,首先在項目配置的模板根路徑尋找(我們項目中配的是 templates 文件夾),沒有找到的話,再去應用的 templates 目錄下尋找。分頁模板預定義的路徑為 pure_pagination/pagination.html,所以我們可以在項目模板根路徑下建立一個一模一樣的文件結構,這樣 django 就會首先找到我們的模板,從而應用我們自定義的模板,而不是預定義的模板。

在 templates 目錄下新建一個 pure_pagination\ 目錄,然后建立一個 pagination.html 文件。

接下來便是在模板中設置分頁導航了,將導航條的七個部分的數據一一展現即可,示例代碼如下:

<div class="text-center pagination" style="width: 100%">
  <ul>
    {% if page_obj.has_previous %}
      <li><a href="?{{ page_obj.previous_page_number.querystring }}"
             class="prev">&lsaquo;&lsaquo; </a></li>
    {% else %}
      <li><span class="disabled prev">&lsaquo;&lsaquo; </span></li>
    {% endif %}
    {% for page in page_obj.pages %}
      {% if page %}
        {% ifequal page page_obj.number %}
          <li class="current"><a href="#">{{ page }}</a></li>
        {% else %}
          <li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
        {% endifequal %}
      {% else %}
        ...
      {% endif %}
    {% endfor %}
    {% if page_obj.has_next %}
      <li><a href="?{{ page_obj.next_page_number.querystring }}" class="next"> &rsaquo;&rsaquo;</a>
      </li>
    {% else %}
      <li><span class="disabled next"> &rsaquo;&rsaquo;</span></li>
    {% endif %}
  </ul>
</div>

多添加幾篇文章,在示例中就可以看到分頁效果了。要使分頁導航更加美觀,通過設置其 CSS 樣式即可。


『講解開源項目系列』——讓對開源項目感興趣的人不再畏懼、讓開源項目的發起者不再孤單。跟着我們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎留言聯系我們、加入我們,讓更多人愛上開源、貢獻開源~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM