はじめに
七尾百合子さん、お誕生日 70日目 おめでとうございます! nikkieです。
オンラインで開催しているDjangoもくもく会で取り組みました1
目次
Django Ninja 🥷
PyCon JP 2024 や DjangoCongress JP 2025 でたびたびその名を見かけていました
Django Ninja、コミュニティに例が少なそうというのはあれど、FastAPIの知識活かせそう & 認証はDjangoの電池同梱を使えそうで、めちゃよさそうでした。発表ありがとうございました #djangocongress
— nikkie(にっきー) / にっP (@ftnext) 2025年2月22日
にんにん!!
DjangoでFastAPIっぽくAPIを書けるという理解です。
手を動かしてどんなものか掴みたく、もくもくネタに積んでいました2
Hello World
これは爆速でした3
やったこと
- django-ninjaのインストール
- 今回uvでやっています
- Djangoプロジェクト作成
uv run django-admin startproject myproject
- Djangoアプリケーションを作っていないので、Hello Worldは爆速となっています
- プロジェクトに
api.py
を作り、urls.py
に指定
myproject/api.py
from ninja import NinjaAPI api = NinjaAPI() @api.get("/hello") def hello(request): return "Hello world"
request
引数は、Djangoのビュー関数っぽいですよね
CRUDのうち、ReadとCreateを実装
チュートリアルはHello Worldで終わりです。
DjangoCongress JP 2025の私の発表で作った書籍アプリに育てようと思いました。
Djangoアプリケーション導入
一歩目としてアプリケーションを作ります(uv run myproject/manage.py startapp book_api
)。
プロジェクトのapi.py
はアプリケーション側に移しました。
アプリケーションを作ったことで、ドキュメントのCRUD exampleがピンと来るようになりました。
Djangoモデルを作ればいいのです!
Read
GET /books で書籍全件を返します。
CRUD exampleの「List of objects」より、Djangoモデルのobjects.all()
を返せばよいです。
book_api/models.py
class Book(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) isbn = models.CharField(max_length=17, unique=True) title = models.CharField(max_length=255) page = models.PositiveIntegerField()
book_api/api.py
@api.get("/books", response=list[BookOut]) def get_books(request): books_qs = Book.objects.all() return books_qs
その時に指定するのが、デコレータのresponse
引数。
これでレスポンススキーマを指定しています。
レスポンススキーマは自分で定義しています。
FastAPIでもやる、PydanticのBaseModelを継承したクラスのようですね4
from ninja import Schema class BookOut(Schema): id: UUID isbn: str title: str page: int
FastAPIでも経験した5ように、Djangoモデル(ORM)の返すクエリセットをレスポンススキーマに合わせてDjango Ninjaが変換してくれているという理解です。
Create
POST /books で書籍データを新規作成します。
CRUD exampleの「Create」より、クライアントから送られてくるデータをパースすると理解しました。
チュートリアルの中の「Input from the request body」から、入力データのスキーマを定義します。
book_api/api.py
class BookIn(Schema): isbn: str title: str page: int
UUIDはユーザが指定するのではなく、システム側でDB保存時に自動採番としています(モデルのdefault=uuid.uuid4
)。
book_api/api.py
@api.post("/books", response={201: BookOut}) def create_book(request, payload: BookIn): book = Book.objects.create(**payload.dict()) return book
ビュー関数の返り値をレスポンススキーマに変換するだけでなく、ユーザが送信してきたデータもリクエストのスキーマにNinjaが変換してくれるのは大変便利ですね。
書くコードがぐっと減りました。
201 Createdで返したかったので、response
にキーがステータスコード(整数)、値がレスポンススキーマの辞書を指定しました。
ref: https://django-ninja.dev/tutorial/step3/#multiple-response-types
E2Eして、FastAPI版と同じと確認
DBをPostgreSQLに設定して、Djangoのマイグレーションを実行。
E2Eを実行します6。
% gauge run specs Python: 3.12.8 # Bookを登録できる ## /booksにPOSTリクエストを送って、Bookを登録できる ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ # Bookを取得できる ## Bookが1冊も登録されていないとき、/booksへのGETリクエストには200が返る ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ## Bookが登録されているとき、/booksにGETリクエストを送って、Bookを一覧できる ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ Specifications: 2 executed 2 passed 0 failed 0 skipped Scenarios: 3 executed 3 passed 0 failed 0 skipped Total time taken: 563ms
FastAPI製書籍アプリで通ったテストは、Django Ninja製書籍アプリでも通り続けました🙌
今回Django Ninjaで実装したアプリの全容はこちらです
django-ninja、すごかったです。
— nikkie(にっきー) / にっP (@ftnext) 2025年5月25日
Djangoモデルを定義して、APIの入力と出力のSchemaを定義するだけでした。
今日はReadとCreateがシュバババと作れました🥷https://t.co/cRLDAIHyfZ https://t.co/vPYh48y6gz
宿題事項
限られた時間(1時間半程度)でDjango Ninjaを触るため、後回しにした事項が多々あります。
- Djangoの便利なライブラリとの連携
- FastAPIと比較するなら async / await はどうなる?
- 積ん読 Async support - Django Ninja
api.py
だけでなく、Djangoモデルもasync対応にする必要がありそう
- Djangoモデルに加えて、入力と出力で同じようなBookクラスを書きました(全3つ)
BookOut
はpydantic.Field
を使って例示できる?(自動生成ドキュメントをリッチにしたい)
終わりに
Django Ninja、同期のCreateとReadを実装しました。
Djangoモデルを用意して、リクエストとレスポンスのスキーマを定義するだけで、これらを実装できました!
DBまわりはDjangoがカバーしてくれている分、FastAPIより楽ですね9。
これでパフォーマンスもFastAPIに近いのであれば、DRFの代わりに選択されうると思います
最後に宣伝。
Djangoもくもく会、次回は6/29(日)です!
-
↩今日の午後はnibuさんと(他の参加者の方と)オンラインでもくもくします。
— nikkie(にっきー) / にっP (@ftnext) 2025年5月25日
django-ninjaでニンニンの予定🥷
シュババババババ(<- 手裏剣を投げている)
Djangoもくもく会: 5回目 https://t.co/fQRNYAUKgo -
頭ミリオンを発揮
↩俺は仕掛け人だからな。
— nikkie(にっきー) / にっP (@ftnext) 2025年2月22日
エミリーちゃんのためにも、自らにんにん!!🥷https://t.co/Ii80QsSfze - FastAPIのHello Worldにも思うんですが、Hello Worldが劇的に速く作れるというのは(ユーザに価値を届けるアプリケーションを速く作れるかを意味しないので)私への訴求としては弱いですね↩
-
ninja.Schema
はpydantic.BaseModel
を継承しています。ref: https://github.com/vitalik/django-ninja/blob/v1.4.1/ninja/schema.py#L209↩ - ↩
- 直近の取り組みはここで使うためでした ↩
- ↩
- たしかmultiple model Multiple Models with FastAPI - SQLModel↩
- FastAPIではいくつかのライブラリを知る必要がありました ↩