はじめに
七尾百合子さん、お誕生日 104日目 おめでとうございます! nikkieです。
オンラインで開催しているDjangoもくもく会の成果報告エントリです
目次
前回のDjango Ninja 🥷
書籍アプリのReadとCreateをシュババと実装しています
Djangoモデルを用意して、リクエストとレスポンスのスキーマを定義するだけで、同期のReadとCreateは実装できました
FastAPIと比較するなら async / await はどうなる?(宿題事項)
今回はReadとCreateを非同期にしていきます
Django NinjaのAsync support
見つけて積ん読にしていた、ズバリなドキュメントがあります
今回の素振りでは Django 5.2 を使っていますが、asyncなORM APIがサポートされているので簡単に書き換えられました。
参考箇所:Using ORM (Django Ninja)
async viewへの書き換え
最終的なソースコードはこちらです
uvicorn導入
https://django-ninja.dev/guides/async-support/#run
python manage.py runserver ではなく、uvicornを使ってサーバーを起動します。
% uv run uvicorn myproject.asgi:application --reload
myproject/ ├── book_api/ ├── myproject/ └── manage.py
Create
before afterをdiffで示します。
@api.post("/books", response={201: BookOut}) -def create_book(request, payload: BookIn): +async def create_book(request, payload: BookIn): - book = Book.objects.create(**payload.dict()) + # book = await sync_to_async(Book.objects.create)(**payload.dict()) + book = await Book.objects.acreate(**payload.dict()) return book
def->async defに変更(関数内でawaitが使えます)- ORM操作は
create()-> 非同期のacreate()に変更 - Django 4.0までは
sync_to_asyncを使っており、こちらも引き続き動作します
Read
@api.get("/books", response=list[BookOut]) -def get_books(request): +async def get_books(request): - books_qs = Book.objects.all() - return books_qs + # all_books = await sync_to_async(list)(Book.objects.all()) + all_books = [book async for book in Book.objects.all()] + return all_books
- こちらも
async defに変更 *クエリセット(all()の返り値)がasync forでイテレート可能になったようです sync_to_asyncを使う場合は、クエリセットが遅延評価のためにsync_to_async(list)というものが出てくるとのこと
以上を書き換えてE2Eは通り続けました!
終わりに
Django NinjaでReadとCreateをasync viewsで実装できました。
かつてはasgiref.syncのsync_to_asyncを使っていましたが、Django 4.1以降多くのORM操作に非同期APIが用意され、より簡単に書けます!
uvicornについてはFastAPIで使っているので、その知見も活かせそうですね
P.S. Djangoは真に非同期ではない?
今回のもくもくで読んだ範囲のドキュメントには、「トランザクションのORMレベルでの非同期サポートはまだ」という記述がありました。
https://docs.djangoproject.com/ja/5.2/topics/async/#queries-the-orm
トランザクションは非同期モードではまだ機能しません。もしトランザクションの動作が必要なコードがある場合は、そのコードを1つの同期的な関数として書いて、
sync_to_async()を使用して呼び出すことをおすすめします。
「非同期対応、まだ終わらないのかな?」という疑問には、DjangoCongress JP 2025の「The Async Django ORM: Where Is it?」という発表が回答になっていそうです
NotebookLMに入れたところ、そもそもORMの非同期APIも真の非同期ではないようです(トークを聞いて理解を深めたい)。
Django Ninja、書き味はかなりFastAPIですが、Django自体が真に非同期にできていないのならパフォーマンスに影響ありそうですね...