コンテンツにスキップ

Djangoの従来のルーティング#

2024 iThome鉄人レース

これはDjango Ninjaシリーズチュートリアルの第7回です。シリーズの第3章に入ります。

第3章は全シリーズの目玉です。なぜなら、Django Ninjaの中核部分であるAPIについて紹介するからです。

この章を3つのセクションに分けました。

  1. 第1節:ルーティング(Router)
  2. 第2節:リクエスト(Request)
  3. 第3節:レスポンス(Response)

第3章は、全シリーズで唯一セクションが分かれている章でもあります。

それでは、第1節であるルーティングに入りましょう。まずは本節の学習のポイントを把握しておきましょう。

GitHubサンプルプロジェクト#

👉 Django-Ninja-Tutorial


この節の概要#

本節は合計2つの記事で構成されています。

  • 第7回:ルーティング(上)従来のDjangoのルーティング手法
  • 第8回:ルーティング(下)Django Ninjaのルーティング設定

なぜこのような構成にしているのでしょうか?それは、エンドポイントとルーティングがAPIリクエストの起点だからです。

これらがなければ、view関数はリクエストを受け取ることすらできず、ましてやレスポンスを返すこともできません。したがって、API開発を学ぶ入口として、まずルーティング設定を扱う必要があります。

いわゆる「エンドポイント」(endpoints)については、単にAPIが存在するURLだと考えて構いません。

この記事の目的#

次に、Django Ninjaのルーティング設定は、従来のDjangoやDjango REST framework(以下、DRFと略します)のルーティング設定とは大きく異なり、むしろFastAPIやFlaskのスタイルに近いです。

これが、私がDjango Ninjaを学ぶ際に遭遇した最初のハードルでした(なんと言っても、私はDRFを2年間書いていましたから😅)。そのため、基礎を固めて混乱を減らす手助けとなるように、上下の2つの記事に分けて詳細に解説することにしました。

本記事の重点は、Djangoの従来のルーティングの設定方法を紹介することです。それでは始めましょう!


ルーティング(Routers)とは何か#

ルーティング(Router)はWebサービスの重要なコンポーネントの一つであり、クライアント(通常はブラウザ)から送信されたHTTPリクエストを、正しい処理ロジックに対応させる役割を担っています。

Djangoにおいて、ルーティングとは「どのリクエストをどのViewが処理するべきか」を決定するメカニズムです。

クライアントが特定のURL(私たちは「エンドポイント」と呼びます)にアクセスした際、DjangoサーバーはこのURLに基づいて対応する処理関数を見つけ、特定のロジックを実行します。

この「対応付け(mapping)」の過程が、ルーティングの核となる役割です。


Djangoのルーティングの紹介#

Djangoのルーティングメカニズムは主に、urls.pyでの設定を通じて異なる階層のルーティング構造を管理し、1次ルーティングと2次ルーティングを介して、すべてのエンドポイントを統合および組織化します。

ここまでで、Djangoのルーティングにおける3つの重要な要素に触れてきました。

  • 1次ルーティング
  • 2次ルーティング
  • urls.py

以下は、それぞれの紹介です。

1次ルーティング#

1次ルーティングは「プロジェクトレベル」のルーティングであり、通常はDjangoプロジェクトディレクトリ下(つまりサンプルプロジェクトのNinjaForumディレクトリ)のurls.pyに位置しています。

1次ルーティングは主に、それぞれのDjango appに対して個別にアプリ全体で統一された「ルーティングプレフィックス」を追加し、すべてのappからのルーティングを統合するために使用されます。

本プロジェクトを例に挙げると、以下のようになります。

# NinjaForum/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('posts/', include('post.urls')),  # post appのルーティングを処理
    path('users/', include('user.urls')),  # user appのルーティングを処理
]

ここでのurlpatternsはDjangoの1次ルーティングです。これは/posts//users/のパスをそれぞれpostおよびuser appの2次ルーティングに指定し、各appの2次ルーティングの統一プレフィックスとして機能します。

2次ルーティング#

2次ルーティングは各Django appが独自に管理するルーティングです。app自身のview関数に直接対応しています。

# post/urls.py
from django.urls import path
from post import views

urlpatterns = [
    path('', views.get_posts)
    path('<int:post_id>/', views.post_detail),
]

1次ルーティングと2次ルーティングのロジックを再構成すると、上記2つのアプリレベルのルーティングの実際のエンドポイントは以下のようになります。

  1. /posts/:すべての記事を取得する。
  2. /posts/<int:post_id>/:特定の記事の詳細を取得する。

このような階層的なルーティング構造は、URLをより組織的にするだけでなく、異なるappの機能をよりモジュール化させます。

例えば、user appに「ユーザーデータを取得する」APIを新しく追加したい場合、私たちは単にuser appのurls.pyに対応するルーティングを作成するだけでよく、プロジェクトレベルのルーティング設定を変更する必要はありません。


プロジェクトの構造図#

俯瞰的な視点で見ると、より分かりやすいかもしれません。

Djangoの従来のルーティング部分において、サンプルプロジェクト全体のディレクトリとファイル構造は以下の通りです(無関係な部分は省略しています)。

├── NinjaForum
   ├── urls.py  # プロジェクトの1次ルーティング
   ├── ...
├── post
   ├── urls.py  # appの2次ルーティング
   ├── ...
├── user
   ├── urls.py  # appの2次ルーティング
   ├── ...
├── ...

このような構造はDjangoプロジェクトにおいて非常に一般的であり、同時にDRFの標準的な手法でもあります。

プロジェクトの1次ルーティングはグローバルな入り口を担当し、2次ルーティングはapp内のview関数とのペアリングを担当します。このような設計により、プロジェクトの構造はモジュール性と拡張性をさらに備えることになります。


Djangoの従来のルーティングのメリットとデメリット#

Djangoの従来のルーティングメカニズムは、プロジェクトとappレベルのurls.pyを通じて完全なURLパス(エンドポイント)を組織・定義します。このような設計には良い面と悪い面があります。そのメリットとデメリットについて探ってみましょう。

メリット:明確なエンドポイントリスト#

Djangoの従来のルーティングの大きなメリットの一つは、すべてのエンドポイントとルーティングがurls.pyに集約されていることです。これは、開発者が現在のすべてのAPIエンドポイント(app部分)を一目で把握できることを意味します。例えば:

# appレベルのurls.py
from django.urls import path
from . import views

urlpatterns = [
    path('home/', views.home, name='home'),
    path('about/', views.about, name='about'),
    path('contact/', views.contact, name='contact'),
]

urls.pyルーティングディレクトリのようになっており、一目瞭然です。

デメリット:エンドポイントとview関数の照合に往復が必要#

前述の通り、ルーティングはエンドポイントとview関数を接続する役割を担っています。

各エンドポイントは一つのview関数に対応する必要があるため、対応するview関数は通常views.pyに配置されます。

対応のイメージ図(参考用)

これが一つの問題を引き起こします。開発者はurls.pyviews.pyの間を行ったり来たりしなければ、一つのエンドポイントと背後にある実装ロジックを完全に理解することができないのです。

このような「直感的でない」部分は、開発時の認知的負荷を増やすだけでなく、APIを修正する際にエラーを発生させやすくなります。

さらに、プロジェクトの規模が拡大し続けると、urls.py内のエンドポイントリストはますます長くなり、対応するview関数を見つけることが時間のかかる煩雑な作業になり、エラーが発生する可能性をさらに高めます。


まとめ#

本記事では、従来のDjangoのルーティング設計について深く理解し、そのメリットとデメリットを探りました。

このような構造化された設計は、ルーティングの管理をよりモジュール化しますが、同時に大規模なプロジェクトにおけるメンテナンスや可読性の難しさといった問題も引き起こします。

次に、Django Ninjaがどのようにより簡潔なルーティングメカニズムを提供しているかを探り、従来のDjangoのルーティングと比較してみましょう。

The Django Ninja Way#

Django Ninjaは、ルーティングとview関数を処理するためのよりモダンな方法を採用しています。両者を密接に結合し、APIエンドポイントを定義するためのより直感的な手段を提供します。(実のところ、みんなFlaskから学んでいるのです☺️)

これにより、異なるファイル間を切り替える必要性が大幅に減少するだけでなく、コードの可読性とメンテナンス性も向上します。

次回の記事では、Django Ninjaのルーティングメカニズムについて学び、これらの問題をどのように改善しているかを見てみましょう。