Django Ninja: 高速なREST API構築をより簡単に、よりスマートに

Python tutorial - IT technology blog
Python tutorial - IT technology blog

DRF(Django Rest Framework)が時に「重い」と感じる理由

Djangoエコシステムに親しんでいる方なら、Django Rest Framework (DRF) のことはよくご存知でしょう。DRFは標準的で強力、かつ非常に多機能なライブラリです。しかし、その多機能さゆえに「重厚すぎる」という代償が伴うことも少なくありません。複雑なSerializerの定義や、わずか数個のフィールドを返すためだけに何層ものクラスをネストさせる作業は、プロジェクトを必要以上に複雑にしてしまうことがあります。

秒間1,500リクエスト以上を処理する必要があった実プロジェクトで、バリデーションロジックの重さに頭を抱えたことがありました。その時に出会ったのが Django Ninja です。その使用感は、FastAPIの柔軟性をDjangoの堅牢なフレームワークにそのまま持ち込んだかのようでした。

核心的な違いは、Django Ninjaが Type Hints(型ヒント)と Pydantic を活用している点にあります。このアプローチにより、ボイラープレートコード(定型コード)を大幅に削減できます。多くのベンチマークによると、Pydantic v2は従来のDRF Serializerよりも5〜10倍速くデータをパースできるとされています。

Django Ninjaとは何か、なぜ注目すべきなのか?

簡単に言えば、Django NinjaはPython 3のモダンな機能をベースにAPIを構築するためのライブラリです。Djangoを完全に置き換えるものではなく、API通信レイヤーの最適化に特化しています。

新しいマイクロサービスで私がこれを選んでいる理由は以下の通りです:

  • 圧倒的なパフォーマンス: Pydanticのおかげで、データの検証と変換がほぼ一瞬で行われます。
  • ドキュメントの自動生成: コードを書くだけで、/docs エンドポイントにSwagger UIとReDocが自動生成されます。
  • Type Safety(型安全性): VS CodeやPyCharmなどのエディタで完璧なコード補完が効くため、タイピング中にエラーに気づくことができます。
  • Async(非同期)対応: async def を使用して、システムをブロックすることなくI/O待ちタスクを処理できます。

記事管理APIを作ってみよう

そのシンプルさを実感するために、簡単なブログアプリを作成してみましょう。基本的なDjangoプロジェクトはすでに作成済みであることを前提とします。

ステップ1:ライブラリのインストール

pipコマンドで数秒でインストールできます:

pip install django-ninja

ステップ2:データモデルの定義

models.py でシンプルなテーブル構造を定義します:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    is_published = models.BooleanField(default=False)

ステップ3:Pydanticによるスキーマ定義

冗長なSerializer의代わりに、Schema(スキーマ)を使用して入力データと出力データを記述します。schemas.py ファイルを作成します:

from ninja import Schema
from datetime import datetime

class PostIn(Schema):
    title: str
    content: str
    is_published: bool = False

class PostOut(Schema):
    id: int
    title: str
    content: str
    created_at: datetime

InOut を分離することで、データをより厳密に制御できます。パスワードや内部IDなどの機密フィールドを誤って公開してしまう心配もありません。

ステップ4:エンドポイントの実装

api.py では、FastAPIによく似た直感的な記述が可能です:

from ninja import NinjaAPI
from typing import List
from .models import Post
from .schemas import PostIn, PostOut

api = NinjaAPI()

@api.get("/posts", response=List[PostOut])
def list_posts(request):
    return Post.objects.all()

@api.post("/posts", response=PostOut)
def create_post(request, data: PostIn):
    post = Post.objects.create(**data.dict())
    return post

コードは非常に見通しが良く、メンテナンスも容易です。すべてが明確に型定義されています。

ステップ5:ルーティングの設定

最後に、プロジェクトの urls.py にAPIを登録します:

from django.urls import path
from .api import api

urlpatterns = [
    path("api/", api.urls),
]

実践から学んだ教訓:バリデーションと最適化

Django Ninjaで特に気に入っている点は、エラーハンドリングです。ユーザーが誤った形式のデータを送信した場合、システムは自動的に422エラーコードを返し、エラー箇所を詳細に説明します。これらのケースに対して手動で例外処理を書く必要は一切ありません。

現場での教訓:大規模なデータベースを扱う際は、Django ORMの .values().only() を組み合わせてください。Django Ninjaはこれらの辞書形式のデータを非常に高速に処理するため、サーバーメモリの負荷を大幅に削減できます。

Swaggerで動作確認

サーバーを起動して http://127.0.0.1:8000/api/docs にアクセスしてみてください。プロフェッショナルなインタラクティブUIが表示されます。ここでは、Postmanを開かなくてもエンドポイントのテスト(Try it out)が可能です。

おわりに

Django NinjaはDRFを廃止させるために生まれたわけではありません。しかし、スピードと軽量さを優先するプロジェクトにとっては非常に魅力的な選択肢です。冗長なSerializerのコードに疲れているなら、ぜひDjango Ninjaを試してみてください。開発効率が劇的に向上することを保証します。

Share: