分頁(上)Django Ninja 的內建分頁器
2024 iThome 鐵人賽
這是 Django Ninja 系列教學的第 24 篇。
分頁(pagination)功能,就算在資料量較少的小型專案,也具有相當的重要性。
沒分頁,API 照樣能運作——只是效能會受到影響,特別是在資料量大的情況下。
當 API 一次回傳大量資料時,不僅會增加伺服器負擔,還可能導致客戶端處理緩慢,甚至出現超時或記憶體不足等問題。
透過分頁,我們可以避免一次性傳輸大量資料,提高 API 的效能,同時提升使用者的體驗。
這個主題將分為上、下兩篇,介紹如何在 Django Ninja 中實作分頁功能——從內建的分頁器到自定義分頁類別,以滿足不同需求。
本文所有的程式碼變動,可參考這個 PR。
分頁的重要性
分頁的核心作用是將大量資料拆分成小部分傳輸,每次只給一些,從而避免效能問題。
具體而言,分頁能夠幫助我們:
- 減少伺服器壓力:不必一次回傳全部資料,只需處理單個頁面的資料。
- 提升網路傳輸速度:傳輸太大量的資料會增加網路延遲和資料丟失的風險,通過分頁,能有效降低傳輸需求。
- 提升使用者體驗:客戶端可以快速獲取並顯示初步資料,無需等待所有資料傳輸完成。同時,分頁還能減少客戶端處理大量資料的壓力。
因此,無論專案規模大小,實作高效的分頁策略,對 API 的擴充性與使用者體驗,都有明顯幫助。
了解了分頁的重要性後,我們來開始實作吧!
這次的範例 API 是——「取得文章列表」。
因為專案的資料庫中已經有超過 60 筆文章資料,非常適合演示。
什麼?你說你沒有?歡迎參考〈卷 12:請求(四)Request Body 與 Schema 介紹〉結尾的「中場休息與準備」段落。
本篇我們將使用 Django Ninja 內建的PageNumberPagination
分頁器,來實作簡單、有效的分頁功能。自定義部分,則留在下一篇。
Django Ninja 內建的分頁器
在 Django Ninja 中,分頁功能可以透過內建的paginate
裝飾器加上分頁器(即分頁類別)實現。
Django Ninja 提供了兩個內建分頁器,為方便你理解,以下是它們的白話文介紹:
LimitOffsetPagination
:根據「從哪一筆資料開始」和「要抓多少筆資料」來進行分頁,適合資料量很大時使用。例如:「從第 20 筆開始,抓 10 筆資料」。PageNumberPagination
:透過頁碼進行分頁,用戶只需要指定想要的頁數,例如「抓第 2 頁的資料」。每頁的資料數量可以由開發者自行設定。
我個人偏好使用PageNumberPagination
,或自定義一個類似的版本(也就是下一篇的內容)。
但預設的分頁器是LimitOffsetPagination
,所以在使用paginate
裝飾器時,需要你主動聲明第一參數。等一下你就知道了。
在那之前,我們先來回顧「取得文章列表」的 API 現狀。
API 現狀
如下所示,由於尚未實作分頁功能,它會一次性回傳所有文章資料:
1 |
|
這在文章少的時候可以運作如常,但隨著資料量增加,效能將會受到影響。
接下來,我們要透過 Django Ninja 內建的分頁器來改善這個問題。
PageNumberPagination 實作分頁
使用內建的PageNumberPagination
,我們可以輕鬆為 API 加上分頁功能。
只要在 view 函式上使用@paginate
裝飾器並加入參數,如下:
1 | from ninja.pagination import PageNumberPagination, paginate |
我省略了大部分內容,這裡只需要關注分頁的實作。
如前所述,第一參數PageNumberPagination
必須由你主動聲明——如果是用LimitOffsetPagination
則不必。
實作的效果是,每頁改為顯示 10 筆文章,這數量可以透過page_size
參數控制。
咦,那換頁怎麼辦?我們看一下PageNumberPagination
的原始碼:
1 | class PageNumberPagination(AsyncPaginationBase): |
Input
代表請求的查詢參數(下一篇會細論),換句話說,你可以在 URL 的查詢參數(query parameters)中使用參數page
來指定「頁碼」,以達到換頁效果。
測試分頁效果
呼叫 API,並使用?page=2
作為查詢參數,看看效果如何:
符合預期!
回應中顯示的確實是第 2 頁內容——文章 id 從 11 開始,總共 10 筆。
使用內建分頁器的優點與局限
優點
- 只用簡單的分頁裝飾器 + 內建分頁器即可實現分頁,而且可以控制每頁的數量,非常方便且實用。
- 適合不需要複雜自定義的情況。
局限
- 缺乏靈活性,例如我們無法讓使用者指定每頁顯示多少筆資料。
- 回應的欄位與格式是固定的——而且有點簡略。
小結
透過 Django Ninja 內建的分頁器,我們能夠迅速為 API 加入分頁功能,立即實現簡單的分頁需求。
然而,內建分頁器在控制靈活性上有所不足,也無法建立客製化回應。當分頁需求變得複雜時,就顯得有點捉襟見肘。
此時,自定義分頁器會是一個更好的解決方案。
下一篇,我們將探討如何在 Django Ninja 中自定義分頁類別,以滿足這些進階需求。