歡迎來到第三章第二節!
作為 API 的核心邏輯實現,view 函式無疑是 Django Ninja API 的靈魂所在。
Django Ninja 和 FastAPI、Flask 一樣,都是以 Function-Based Views(以下簡稱 FBVs)為主。所以它的學習重點,幾乎都繞圍在 view 函式的 input 和 output。
換句話說,整個 Django Ninja 框架的能力,構成了 view 函式的這些關鍵部分,包括但不限於:
它們共同構成了 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 請求有基本的認識。
我們將透過以下三個重點來讓你逐步熟悉:
話不說多,我們直接開始。
Class-based views (CBVs) 和 FBVs 都是實現 Django MTV 架構 中的 Views 手段,各有其適用場景。
CBVs 有重用程式碼優勢,適合大型專案。而 FBVs 則以簡單、直接為賣點,方便快速開發中小型專案。
兩者的比較,可參考這篇〈Day27 : CBV vs. FBV〉。
因為 Django Ninja 採 FBVs,本文只探討 FBVs 的優點。
FBVs 是 Django Ninja 採用的 view 形式。與 CBVs 相比,FBVs 更加簡潔、靈活,能夠讓開發者輕鬆編寫出 API 邏輯而不需要了解太多背景知識,比如「如何正確覆寫某個 CBV 屬性」。
FBVs 不需要繼承或覆寫類別方法,所有的邏輯都集中在一個函式中。
這使得寫作和維護程式碼更加直觀。
由於 FBVs 本質是個函式,它可以更靈活地應用各種邏輯和條件,開發者能在單一函式中完全控制整個請求的處理流程,而不需要考慮類別的結構或繼承關係。
FBVs 的程式碼相對直觀,對於初學者來說,閱讀、理解起來更加容易。發生錯誤時,你可以快速定位問題,這是 CBVs 不易達到的便利性。
Django 是個功能全面的框架,但也常被批評為「笨重」。FBVs 在一定程度上緩解了這種笨重感。
試想,一個剛接觸 Django 的新手,在理解完各種框架的環境設定後,還要深入 CBVs 的世界,是否太過沉重?
總之,如果你問我,我絕對更偏好 FBVs——而且「輕量化」是現代開發的趨勢。
Django Ninja 對「請求」的處理可以分為幾個關鍵步驟:
上述第 1 點已在本章第一節詳細解說。
第 2 和第 3 點則是本節共 4 篇文章的主要內容。
Django Ninja 非常依賴 Python 的 type hints 來處理 HTTP 請求中的資料。
並透過 Pydantic 實現了自動資料驗證和類別轉換,減少了開發者手動檢查和轉換資料的負擔。
例如以下程式碼:
@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
。
在 Django 中,view 函式的第一個參數必定為 request。這個參數名稱可以自行定義,但通常會命名為request
。
收到 HTTP 請求時,Django 會將整個請求打包成一個HttpRequest
物件,並將它作為第一個參數傳給 view 函式,所以它必不可少。
request
參數在 Django 和 Django REST framework 中非常重要,因為它常用來取得請求的查詢參數、body 等內容。
在 Django Ninja 中,這些資料會直接透過函式參數來取得,因此request
雖然仍不可少,但使用頻率較低。
接下來,我們將深入探討 Django Ninja 處理請求的具體細節。
下一篇將聚焦於路徑參數(path parameters),並探討如何與 Django 原生的 path converters 搭配使用。敬請期待!
本文同步發表於我的部落格——Code and Me
目前好像還沒說明 view function 中的 request 參數是做什的? 還是這是伏筆後面會講
是否每個 view function 一定要有這個 request? (以 FastAPI 來說是非必要,有需要用上才填即可)
如果一定要有的話是否一定要填在第一個參數? 另外沒有提供它的 Type Hints,mypy 應該會該該叫吧🤣
哈哈哈,你看得很細耶!佩服佩服
本來打了一串要回你,但仔細想想,確實應該要直接補充在文章中。我自己習以為常,但讀者——尤其是沒用過 Django 的人,應該會和你有同樣的困惑,這無疑是我的疏忽
看來看去,還是補充在本篇最適合(因為是請求總論)
我剛剛已經新增了「View 函式中的 request 參數」在倒數第二段
request 的 type hints 我沒有加上去,因為怕程式碼資訊過多,後續的程式碼都會補上
其實 return type 也還沒寫
return type 在 fastapi 也可以是有意義的,它能夠幫你打包成對應的樣子並驗證回傳是否符合預期(或者將 schema 顯示在 api docs 上),不確定 Ninja 有沒有相似功能,等待後續介紹 😆
我看了你補充的內文了,request 確實不常用,但卻每個都要填,確實偶爾也會覺得挺煩的。
這種框架必填參數但該 func 又沒用到,我會把它命名為 _
~~不然又換我的 ruff ARG001 又要該該叫 ~~,有用上就會命名成 request
這種時候命名底線還有個好處就是有時候就剛好多那幾個字母 linter 就要換行,有時候換行超醜的
不確定 Ninja 有沒有相似功能,等待後續介紹 😆
有的,畢竟 Django Ninja 是「抄」FastAPI 的嘛!哈哈哈
在 Django Ninja 的原始碼中,有一個 TODO 是考慮讓 request 參數變成可選(類似 FastAPI),但這畢竟和 Django 的預設不同,我猜大概短期內都不會實作
這種框架必填參數但該 func 又沒用到,我會把它命名為 _ ~~不然又換我的 ruff ARG001 又要該該叫 ~~,有用上就會命名成 request
這倒是一個不錯的辦法,很能夠體現作為開發者的細心唷!