Django Ninja 30:系列回顧與完賽心得

2024 iThome 鐵人賽

這是 Django Ninja 系列教學第 30 篇。

系列最終章,我們的「Django Ninja 探險」將暫時告一段落。

這當然不是結束,畢竟 Django Ninja 還只是一個相對新的專案——我對它的未來充滿期待。

本文將分為兩個部分:

  1. 回顧整個系列,檢視我們在各章中學到的概念與技術——盡可能只提重點。
  2. 分享我在寫作過程中的最大挑戰、對 Django Ninja 的期待,最後則是我的鐵人賽完賽心得。

受限於篇幅,更多的幕後花絮、創作細節及個人心得,我將在與正賽無關的第 31、32 篇中,再行分享。

此外,我還會不定期更新「Django Ninja 番外篇」,補充正篇中未能詳述的內容。有興趣的讀者,歡迎訂閱本系列唷!

話不多說,我們直接開始。


一、系列目標與主要學習成果

回到第 1 篇的開頭,整個系列的目標是:

在這個 30 天的系列文章中,我們將詳細探討 Django Ninja 的基礎實作,透過文字教學範例專案的程式碼,帶你一步一步熟悉這個強大而靈活的 Django API 開發框架。

沒錯,而我們具體做了哪些事呢?

主要學習成果

透過本系列,讀者掌握了以下 Django Ninja 核心技能:

  1. 設定 Django Ninja 路由。(卷 7-8)
  2. 處理各種 HTTP 請求及參數——路徑參數、查詢參數、body。(卷 9-12)
  3. 使用 Schema 設計和定義 API 回應的資料結構。(卷 13-16)
  4. 從專案程式碼自動產生 API 文件、透過 Pydantic 驗證資料、有效處理系統拋出的錯誤。(卷 17-22)
  5. 靈活運用進階功能,包括檔案上傳、分頁和資料過濾。(卷 23-27)

還有最後的身分認證與單元測試。可說是一段相當完整的旅程

單元測試——使用 Test Client 與 pytest 測試 API

2024 iThome 鐵人賽

這是 Django Ninja 系列教學第 29 篇。

「請問你們的專案有單元測試嗎?」

面試中如果你提出這個問題,可能會讓面試官面有難色。

測試的重要性,大部分開發者都心知肚明。只是願意認真對待的人未必很多。

但如果真心想提高程式碼品質、減少 bug,讓專案更容易維護,那單元測試依舊是不可或缺的工具。

良好的測試不僅能幫助我們及早發現問題,還能在專案重構或新增功能時,確保現有的功能不會被破壞。

雖然寫測試會增加初期的開發時間,而且維護上也需要花費心力——這本來就不是一件輕鬆的事。但長期而言,它能為專案帶來持續的健全與穩定性。

所以,我們還是好好寫測試吧!


本文大綱

這是整個系列中唯一一篇有全文大綱的教學。

原因是,本文要提及的事項較多,畢竟單元測試這麼大的主題,怎麼可能靠一篇 2500 字的文章說完。限於篇幅,無法一一詳談——但也不能直接省略。

所以需要有一個供讀者鳥瞰的全文輪廓,讓你更容易了解、吸收。大綱如下:

  1. 單元測試的理想與現實。
  2. Django API 測試重要概念說明。
    • Test Client 的意義與用途。
    • pytest 和 pytest-django 簡介。
    • pytest fixtures 與測試函式。
  3. 測試程式碼的實作與解說。
  4. 結語。

簡單來說,本文不會講解所有的程式碼改動,而是在必要時提及。其餘部分,由我直接實作並收錄在範例專案中,讓讀者自行參考。

在有限的篇幅中,帶你了解整體概念比關注細節更重要。當你掌握了基本概念,再去看程式碼會更加得心應手。

有關單元測試的更多討論,歡迎參考這篇心得〈《Python 工匠》筆記(二)對「單元測試」的看法與建議〉。這是一本立論紮實的好書,相信你會有所收獲。

本文所有的程式碼改動,可參考這個 PR

身分認證——Session 認證與全域設定

2024 iThome 鐵人賽

這是 Django Ninja 系列教學第 28 篇。

歡迎來到第七章!本章總共有兩篇內容:

  • 卷 28:身分認證——Session 認證與全域設定
  • 卷 29:單元測試——使用 Test Client 與 pytest 測試 API

這些主題的核心功能,並非由 Django Ninja 實作,但框架仍提供了一定程度的整合。並且,這些功能對於任何 Django 專案來說,都至關重要。

本文介紹幾乎所有 API 專案都需要的——身分認證Authentication)。

我們將探討如何在 Django Ninja 中利用 Django 內建的 session-based 認證,實現完整的登入驗證功能,並進一步說明如何設定全域認證,以減少程式碼的重複。

本文所有的程式碼改動,可參考這個 PR


認證的兩個層次

進入實作前,我們要先了解,所謂的身分認證,究竟代表什麼。

以「帳號密碼 + session 認證」為例,身分認證的範圍主要涵蓋兩個階段

首先,當使用者透過帳號密碼進行登入時,系統會檢查這些內容、確認身分合法。登入成功後,系統會將使用者資訊(比如用戶 id)儲存至 session,以維持登入狀態

這是登入時的認證,也是我們最常說的認證。(狹義的認證

接著,當使用者嘗試存取受「認證保護」的 API 時,系統會檢查 session 並確認身分,確保每個 API 請求都來自合法登入的使用者。

簡言之:

  • 第一階段:初次登入時的身分確認。
  • 第二階段:後續請求時的身分確認。

兩個層次相輔相成、一體兩面,確保服務能夠在使用者登入後續操作中,提供適當的安全保障。

資料查詢與過濾(下)FilterSchema 多欄位查詢

2024 iThome 鐵人賽

這是 Django Ninja 系列教學第 27 篇。

上篇中,我們學習了 Django ORM 的Q物件和 Django Ninja 的 FilterSchema,但後者感覺只學了一半。

討論比較多的是,view 函式中使用 FilterSchema 的參數定義方式——這確實很重要,但這只是 FilterSchema 的一部分。

本篇要來補完剩下的內容:

  1. 完善 FilterSchema:使用「更道地」的寫法,釋放 FilterSchema 真正的力量
  2. 實作更進階的欄位查詢功能:多欄位查詢——篩選日期區間。
  3. 追加實作第 20 篇學到的「跨欄位驗證」:驗證查詢參數的日期區間是否合法

看來又是資訊滿滿的一篇,話不多說,直接開始吧!

本文所有的程式碼變動,可參考這個 PR

資料查詢與過濾(上)FilterSchema 介紹

2024 iThome 鐵人賽

這是 Django Ninja 系列教學第 26 篇。

查詢」是 API 中常見的附加需求,本質上是對資料的過濾(filtering)與篩選

無論是篩選文章、商品,還是查詢用戶,根據不同條件來過濾資料並獲得結果,可說是大部分專案的必備功能。

在 view 函式中,實作查詢最簡單的方式,就是使用 Django ORM 的過濾方法。例如,我們可以用filter方法來根據特定條件篩選 QuerySet。

這種方法簡單直接,適合基本的查詢需求。然而,它也有其局限性——隨著欄位與需求的增加,查詢條件可能變得越來越複雜,導致程式碼冗長且難以維護。

為了解決這一問題,Django Ninja 提供了 FilterSchema,讓我們可以用更「結構化」的方式,定義並管理查詢條件。

本文將介紹 FilterSchema,一步步實作與講解,讓你了解如何在 Django Ninja 中使用 FilterSchema,實現更加靈活、模組化的 API 查詢功能。

本文所有的程式碼改動,可參考這個 PR

分頁(下)自定義分頁類別

2024 iThome 鐵人賽

這是 Django Ninja 系列教學第 25 篇。

上一篇我們介紹了 Django Ninja 的內建分頁器,並用它實作了簡單的分頁功能。

雖然內建的PageNumberPagination確實方便,但在很多時候,我們仍需要一些客製化功能。

為了實現這個目的,你需要自定義一個分頁類別

不過別擔心,這種自定義,並非從零開始。而是繼承 Django Ninja 所提供的基礎分頁類別,再進行自己的「加工」。

這篇文章就要來教你怎麼做。

本文所有的程式碼變動,可參考這個 PR


客製化需求

除了基本的分頁,我們還希望能夠:

  • 允許客戶端選擇每頁顯示的資料數量,可選範圍限定在 1 至 100 之間。
  • 在回應中新增兩個欄位,顯示當前的分頁資訊
    • 當前頁數(page)。
    • 每頁顯示數量(per_page)。

這無疑是很常見的需求。我們將透過自定義分頁類別,來實現這些功能。

話不多說,直接開始!

分頁(上)Django Ninja 的內建分頁器

2024 iThome 鐵人賽

這是 Django Ninja 系列教學第 24 篇。

分頁(pagination)功能,就算在資料量較少的小型專案,也具有相當的重要性。

沒分頁,API 照樣能運作——只是效能會受到影響,特別是在資料量大的情況下。

當 API 一次回傳大量資料時,不僅會增加伺服器負擔,還可能導致客戶端處理緩慢,甚至出現超時記憶體不足等問題。

透過分頁,我們可以避免一次性傳輸大量資料,提高 API 的效能,同時提升使用者的體驗。

這個主題將分為上、下兩篇,介紹如何在 Django Ninja 中實作分頁功能——從內建的分頁器自定義分頁類別,以滿足不同需求。

本文所有的程式碼變動,可參考這個 PR


分頁的重要性

分頁的核心作用將大量資料拆分成小部分傳輸,每次只給一些,從而避免效能問題。

具體而言,分頁能夠幫助我們:

  1. 減少伺服器壓力:不必一次回傳全部資料,只需處理單個頁面的資料。
  2. 提升網路傳輸速度:傳輸太大量的資料會增加網路延遲和資料丟失的風險,通過分頁,能有效降低傳輸需求
  3. 提升使用者體驗:客戶端可以快速獲取並顯示初步資料,無需等待所有資料傳輸完成。同時,分頁還能減少客戶端處理大量資料的壓力

因此,無論專案規模大小,實作高效的分頁策略,對 API 的擴充性與使用者體驗,都有明顯幫助

了解了分頁的重要性後,我們來開始實作吧!