2024 iThome 鐵人賽2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 9 篇。

歡迎來到第三章第二節!

作為 API 的核心邏輯實現,view 函式無疑是 Django Ninja API 的靈魂所在。

Django Ninja 和 FastAPI、Flask 一樣,主要是採用 function-based views(以下簡稱 FBVs)。所以它的學習重點,幾乎都繞圍在 view 函式的 input 和 output。

換句話說,整個 Django Ninja 框架的能力,構成了 view 函式的這些關鍵部分,包括但不限於:

  1. 處理 HTTP 請求的參數與 body。
  2. 處理 HTTP 回應內容的序列化與格式化。
  3. 資料驗證與錯誤處理。

它們共同構成了 Django Ninja 的主要功能。

本節和下一節,將集中討論上述 3 點中的前兩點——請求與回應。至於第三點,將留到第五章再行介紹。


本節導覽

繼上一節的「路由」後,本節將探討 Django Ninja 如何處理 HTTP 請求——如何解析 path、URL 查詢參數和 body。

本節一共有 4 篇:

此外,因為 view 函式處理請求功能,已涉及 Django Ninja 如何使用 type hints 來驗證請求資料。我們的範例程式碼會開始加上 Python 型別提示

Type hints 的語法以 Python 3.12 為準。

官方文件

本系列的寫作不時會參考「Django Ninja 官方文件」,尤其是架構的呈現。

但文件畢竟是給全體開發者看的,並沒有充分考慮到學習的順序。

而本列系主要面向入門者,所以我們會更加注重實際操作與入門者的需求,並適時補充一些背景知識,確保學習曲線能相對平緩

此外,就框架本身,我們也會提供更多實例和解釋,讓新概念更好理解和掌握。

但無論如何,官方文件仍是你在使用 Django Ninja 時,需要時時參考的內容——雖然它寫得比 Django 或 Django REST framework 的文件,相對「簡單」很多!


本文主旨

本文作為第二節的概論,目標是讓你對 Django Ninja 的 view 函式與它如何處理 HTTP 請求有基本的認識

我們將透過以下三個重點來讓你逐步熟悉:

  1. FBVs 的優點。
  2. Django Ninja 對 HTTP 請求的處理流程。
  3. Django Ninja 與 Type Hints 的緊密結合。

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


Class-based views (CBVs) 和 FBVs 都是實現 Django MTV 架構 中的 Views 手段,各有其適用場景。

CBVs 有重用程式碼優勢,適合大型專案。而 FBVs 則以簡單、直接為賣點,方便快速開發中小型專案。

兩者的比較,可參考這篇〈Day27 : CBV vs. FBV〉。

因為 Django Ninja 採 FBVs,本文只探討 FBVs 的優點。

一、FBV 的優點

FBVs 是 Django Ninja 採用的 view 形式。與 CBVs 相比,FBVs 更加簡潔、靈活,能夠讓開發者輕鬆編寫出 API 邏輯而不需要了解太多背景知識,比如「如何正確覆寫某個 CBV 屬性」。

簡潔與靈活

FBVs 不需要繼承或覆寫類別方法,所有的邏輯都集中在一個函式中。

這使得寫作和維護程式碼更加直觀。

由於 FBVs 本質是個函式,它可以更靈活地應用各種邏輯和條件,開發者能在單一函式中完全控制整個請求的處理流程,而不需要考慮類別的結構或繼承關係

容易 Debug

FBVs 的程式碼相對直觀,對於初學者來說,閱讀、理解起來更加容易。發生錯誤時,你可以快速定位問題,這是 CBVs 不易達到的便利性。

我的看法

Django 是個功能全面的框架,但也常被批評為「笨重」。FBVs 在一定程度上緩解了這種笨重感

試想,一個剛接觸 Django 的新手,在理解完各種框架的環境設定後,還要深入 CBVs 的世界,是否太過沉重?

總之,如果你問我,我絕對更偏好 FBVs——而且「輕量化」是現代開發的趨勢。


二、Django Ninja 對 HTTP 請求的處理流程

Django Ninja 對「請求」的處理可以分為幾個關鍵步驟:

  1. 路由配對:當請求進來時,框架首先會將來源 URL 與定義的路徑規則(端點)進行配對。若配對成功,則將 HTTP 請求與相關參數傳遞給 view 函式。
  2. 參數解析:從 URL 中提取路徑參數path parameters)和查詢參數query parameters),將它們轉換為 view 函式的「引數」(arguments)。根據函式的 type hints 自動進行型別轉換和驗證。
  3. Request body 處理:對於 POST 或 PUT 等帶有 body 的請求,Django Ninja 讓開發者使用 Schema(Pydantic BaseModel)定義 body 資料模型,並自動將傳入的資料對應到這些模型。

Django Ninja 處理 HTTP 請求流程Django Ninja 處理 HTTP 請求流程

上述第 1 點已在本章第一節詳細解說。

第 2 和第 3 點則是本節共 4 篇文章的主要內容。


三、Django Ninja 與 Type Hints 的緊密結合

Django Ninja 非常依賴 Python 的 type hints 來處理 HTTP 請求中的資料。

並透過 Pydantic 實現了自動資料驗證類別轉換,減少了開發者手動檢查和轉換資料的負擔。

例如以下程式碼:

1
2
3
@router.get("/posts/{post_id}")
def get_post(request, post_id: int):
return {"post_id": post_id}

post_id參數被標記為int時,Django Ninja 會進行型別檢查。如果傳入的參數無法轉換為int,框架會直接返回狀態碼為 422 的 HTTP 回應。

換言之,如果你將post_id標記為str,則 Django Ninja 會自動將post_id轉換為字串。

還記得剛開始接觸 Django Ninja時,我非常驚嘆竟然可以充分運用 Python type hints 到這般程度,讓它不僅僅是為了型別安全而服務,而是融入到整個 API 開發流程中

View 函式中的 request 參數

上面的例子中,有個值得注意的細節,就是 view 函式的第一參數——request

在 Django 中,view 函式的第一個參數必定為 request。這個參數名稱可以自行定義,但通常會命名為request

收到 HTTP 請求時,Django 會將整個請求打包成一個HttpRequest物件,並將它作為第一個參數傳給 view 函式,所以它必不可少

相關文章:Django HttpRequest 常用屬性介紹

request參數在 Django 和 Django REST framework 中非常重要,因為它常用來取得請求的查詢參數、body 等內容。

在 Django Ninja 中,這些資料會直接透過函式參數來取得,因此request雖然仍不可少,但使用頻率較低


下一步

接下來,我們將深入探討 Django Ninja 處理請求的具體細節

下一篇將聚焦於路徑參數path parameters),並探討如何與 Django 原生的 path converters 搭配使用。敬請期待!