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

2024 iThome 鐵人賽

系列最終章,我們的「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)

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

Django Ninja 教學 29:單元測試——使用 Test Client 與 pytest 測試 API

2024 iThome 鐵人賽

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

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

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

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

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

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

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


本文大綱

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

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

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

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

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

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

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

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

Django Ninja 教學 28:身分認證——Session 認證與全域設定

2024 iThome 鐵人賽

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

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

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

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

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

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


認證的兩個層次

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

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

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

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

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

簡言之:

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

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

Django Ninja 教學 27:資料查詢與過濾(下)FilterSchema 多欄位查詢

2024 iThome 鐵人賽

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

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

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

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

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

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

Django Ninja 教學 26:資料查詢與過濾(上)FilterSchema 介紹

2024 iThome 鐵人賽

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

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

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

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

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

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

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

Django Ninja 教學 25:分頁(下)自定義分頁類別

2024 iThome 鐵人賽

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

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

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

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

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

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


客製化需求

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

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

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

話不多說,直接開始!

Django Ninja 教學 24:分頁(上)Django Ninja 的內建分頁器

2024 iThome 鐵人賽

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

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

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

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

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

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


分頁的重要性

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

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

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

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

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