路由(下)Django Ninja 路由設定
2024 iThome 鐵人賽
這是 Django Ninja 系列教學的第 8 篇。
上一篇文章中,我們介紹了 Django 傳統的路由設定方式。
如前所述,雖然有一個「路由清單」確實不錯。但隨著專案規模的擴大,不斷來回切換urls.py
和views.py
將大幅增加開發者的認知負擔——拉長了開發時間,還更容易導致錯誤。
Django Ninja 採用了一種更現代化的路由設計,結合了 Flask 和 FastAPI 的設計理念。不僅簡化了路由的定義,還提升了程式碼的可讀性,讓路由與 view 函式緊密結合。
範例專案動態
本文關於路由設定的程式碼改動,可以參考這個 PR(Pull Request)。
範例專案合併了本文的 PR 後,已經正式成為一個「API 專案」,不過它目前(指這個 commit 狀態)尚無法正常運作,因為我們還沒有完善 view 函式的基本功能。
你可以一步步地跟著每一篇的 PR,來學習當次的新內容。這也是我為文章建立 PR 的用意所在。
快速導覽
👉 完整系列目錄:點此查看
👉 程式碼範例:GitHub 範例專案
現在,我們開始介紹 Django Ninja 的路由設定。
Django Ninja 路由概述
Django Ninja 使用 Python 裝飾器(decorator)來定義路由和 HTTP 方法。這種方式將路由與 view 函式緊密結合,大大提高了程式碼的可讀性。
熟悉 Python 的都知道,其實這種「使用裝飾器定義路由」的方式,最早來自 Flask。作為一個輕量級框架,Flask 率先引入了這種簡潔優雅的設計,堪稱典範級的創舉。
這個設計後續被其他框架採用,比如 FastAPI 和本文的 Django Ninja,都繼承了這種靈活的路由定義模式。
在 Flask 中,開發者可以這樣定義路由:
1 | from flask import Flask |
Django Ninja 也採用了類似的概念,只是在語法上更融入 Django 生態,並結合了型別提示(type hint)和 Pydantic 的資料驗證功能,讓 API 開發變得更加現代化。
以下是 Django Ninja 的一個簡單範例:
1 | from ninja import NinjaAPI |
Flask 與 Django Ninja 這兩種寫法,與其說非常相似,不如說一模一樣😎
更有組織的做法:使用 Router 物件
雖然直接使用上述範例中的NinjaAPI
來定義路由簡單而直觀。但實際工作中,我們更推薦使用Router
物件(官方文件)來管理不同 Django app 的路由。
1 | from ninja import Router |
這和 Django 傳統做法中「區分一級與二級路由」的基本精神相符。不僅讓專案的架構保持清晰,還能讓每個 app 的邏輯獨立。
在 Django Ninja 中,Router
物件提供了一種模組化的路由設定方式,讓每個 Django app 可以管理自己的路由,並在專案層級的api.py
統一整合起來——也就是取代傳統的urls.py
功能。
以下程式碼範例,我們都會以Router
物件來實作。
專案架構變化
先來看看採用 Django Ninja 以後,傳統 Django 專案的結構會有怎麼樣的變化。
Django 傳統路由結構
以範例專案為例,這是傳統 Django 的典型結構:
1 | ├── NinjaForum |
Django app 層級的urls.py
負責定義所有 app 內的路由,然後再由專案的urls.py
進行統合。井然有序,權責分明。
Django Ninja 路由結構
在採用 Django Ninja 後,專案結構會有一些變化。以下是一個典型的 Django Ninja 專案結構:
1 | ├── NinjaForum |
在這個結構中,每個 Django app 都有一個api.py
,用於定義該 app 的所有 API 路由和 view 函式,取代了傳統 Django 中的urls.py
和views.py
的功能。
專案級別的api.py
則負責整合所有 Django app 的 API。
此外,專案的urls.py
仍然是必要的,它負責將 Django Ninja 的 API 路由再整合到 Django 的 URL 設定中。同時,還可以化身為「零級」路由,為所有 API 加上全專案統一的路由前綴,比如/api/
。
Django Ninja 路由實作
了解了 Django Ninja 的路由結構,我們直接在範例專案的兩個 Django app 分別實作「取得所有使用者」和「取得文章列表」兩個 API。
我們會在接下來的數篇文章中,循序漸進地完善這些 API。目前只是雛形,先把焦點放在路由設定上。
一、建立二級路由
在 user app 中建立一個api.py
, 內容為:
1 | # user/api.py |
同理,我們在post/api.py
中建立類似的路由與 view 函式:
1 | # post/api.py |
這樣,我們就為 user 和 post 兩個 app 分別建立了 API。接下來,我們需要將這些路由整合到專案級別的 API 路由中。
二、建立一級路由
在 Django 專案目錄(指 NinjaForum 目錄)底下,我們也需要建立一個api.py
。它將作為我們的一級路由,整合所有 app 的 API。以下是這個api.py
的內容:
1 | # NinjaForum/api.py |
值得留意的是,這裡的路由整合有兩種寫法,上面我習慣使用的。
另一種寫法是直接 import router
物件:
1 | from user.api import router as user_router |
這兩種方法在功能上是等效的,選擇哪種主要取決於個人偏好和專案的組織方式。
三、專案 urls.py
在 Django Ninja 中,專案層級的urls.py
化身為連接 Django 和 Django Ninja API 的橋梁。
在專案urls.py
中,我們還能再定義全專案共用的路由前綴。長這樣:
1 | from django.contrib import admin |
這裡定義了一個專案路由前綴——/api/
。
如此一來,「取得所有文章」的 API 端點將會是:
1 | /api/posts/ |
當然,如果你不需要額外的路由前綴,也可以直接省略:
1 | urlpatterns = [ |
至此,我們完成了 Django Ninja 的路由設定。
這樣的結構不僅保持了 Django 原有的模組化設計,還為我們的 API 開發提供了更大的靈活性。
本節收尾與下一步
在第一節中,我們學習了如何使用 Django Ninja 定義路由,並了解 Django 傳統路由與 Django Ninja 路由的差異。
Django Ninja 的路由做法不僅讓程式碼更具可讀性,還保持了專案的清晰結構,改善了 Django 傳統路由的一些缺點。
下一篇,我們將進入 Django Ninja API 的核心部分——view 函式。