こんにちは、かつコーチです。
前回の記事でDjangoのディレクトリ構成を紹介した際、「urls.pyはルーティングの起点になる」と説明しました。
この記事では、実際にurls.pyを編集しながら、URLと処理を結びつけるルーティング(どのURLにアクセスされたら、どの処理を実行するかの対応付け)の基本を解説します。
urls.pyの役割とは?
ルーティングとは何か
ルーティングとは、ブラウザから送られてきたURL(例:/blog/1/)を見て、「このURLならこの処理を実行する」と振り分ける仕組みのことです。
Djangoでは、この振り分けルールをurls.pyというファイルに記述します。
プロジェクトのurls.pyとアプリのurls.py
Djangoのルーティングには、2つのurls.pyが登場するのが特徴です。
- プロジェクトのurls.py(
config/urls.py):プロジェクト全体の入り口。どのアプリにルーティングを振り分けるかを管理する - アプリのurls.py(
blog/urls.py):各アプリの中で、さらに細かくURLを振り分ける。デフォルトでは生成されないため自分で作成する
この2段階構成にすることで、アプリごとにURL設定を独立させられ、複数のアプリを組み合わせたときにも管理がしやすくなります。
urls.pyの基本の書き方
手順1:アプリのurls.pyを作成する
blogアプリの中に、urls.pyという名前でファイルを新規作成します。
# blog/urls.py
from django.urls import path
from . import views
app_name = "blog"
urlpatterns = [
path("", views.index, name="index"),
path("<int:pk>/", views.detail, name="detail"),
]
path()関数の第1引数がURLのパターン、第2引数が呼び出す処理(View)、nameは後でURLを参照するときに使う名前です。<int:pk>/のような書き方はパスコンバータと呼ばれ、URLの一部を数値として受け取り、Viewに引数として渡してくれます。
手順2:プロジェクトのurls.pyから読み込む
作成したアプリのurls.pyを、プロジェクト全体のurls.pyから読み込むように設定します。
# config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("blog/", include("blog.urls")),
]
include()を使うことで、「/blog/から始まるURLはblog/urls.pyに処理を任せる」という委譲ができます。
これにより、/blog/にアクセスするとblog/urls.pyのpath("", ...)が、/blog/1/にアクセスするとpath("<int:pk>/", ...)が呼ばれる仕組みです。
手順3:対応するViewを用意する
urls.pyが参照しているviews.py側にも、対応する処理を書いておく必要があります。
# blog/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("ブログ記事の一覧ページです")
def detail(request, pk):
return HttpResponse(f"{pk}番の記事詳細ページです")
ここまで書けたら、開発サーバーを起動してhttp://127.0.0.1:8000/blog/とhttp://127.0.0.1:8000/blog/1/にアクセスし、それぞれ別の文章が表示されることを確認してみましょう。
つまずきやすい設定・注意点
パスコンバータの種類を理解しておく
<int:pk>のように、パスコンバータにはいくつかの種類があります。
| コンバータ | 用途 |
|---|---|
str | デフォルト。スラッシュを含まない文字列 |
int | 0以上の整数 |
slug | 英数字・ハイフン・アンダースコアの文字列(記事URLなどに便利) |
uuid | UUID形式の文字列 |
用途に合わないコンバータを指定すると、意図したURLがマッチせず「404 Not Found」になってしまうので注意しましょう。
name属性を省略すると後で困る
path()のname引数は省略してもエラーにはなりませんが、省略するとテンプレート側でURLを参照する際に困ります。
❌ Before
path("<int:pk>/", views.detail),
# nameがないため、テンプレートでURLを動的に組み立てられない
✅ After
path("<int:pk>/", views.detail, name="detail"),
# {% url 'blog:detail' pk=1 %} のように名前でURLを参照できる
筆者は最初、nameを「あとで付ければいいや」と省略して進めていたところ、テンプレートでリンクを作る段階になって大量に書き直す羽目になりました。
最初からnameを付けておく習慣をつけておくと、後の手戻りを防げます。
よくあるつまずきポイント・エラー対処
app_nameを付け忘れて名前空間エラーになる
❌ Before
NoReverseMatch: 'blog' is not a registered namespace
これは、アプリのurls.pyにapp_nameを設定しないまま、テンプレート側で{% url 'blog:detail' %}のように名前空間付きでURLを参照したときに出るエラーです。
✅ After
# blog/urls.py
app_name = "blog" # この1行を忘れずに
urlpatterns = [
path("<int:pk>/", views.detail, name="detail"),
]
複数のアプリを扱うようになると、detailのような名前が別のアプリでも使われて衝突することがあります。app_nameで名前空間を区切っておくことで、こうした衝突を防げます。
応用・一歩先の使い方
includeの入れ子で大規模プロジェクトにも対応できる
アプリが増えてきた場合、プロジェクトのurls.pyには各アプリへのinclude()だけを並べる形にしておくと、見通しがよくなります。
# config/urls.py
urlpatterns = [
path("admin/", admin.site.urls),
path("blog/", include("blog.urls")),
path("accounts/", include("accounts.urls")),
path("shop/", include("shop.urls")),
]
このように「プロジェクトのurls.pyは交通整理役、各アプリのurls.pyが実際の詳細ルール」という役割分担を徹底すると、アプリ数が増えても管理しやすい構成を保てます。
まとめ
この記事のポイント
- ルーティングは「URL」と「処理(View)」を結びつける仕組み
- Djangoではプロジェクトのurls.pyとアプリのurls.pyの2段階構成が基本
include()でアプリ単位にルーティングを委譲するpath()のnameとapp_nameは最初から設定しておくと後で困らない
次に読むべき記事
URLと処理の結びつけ方が分かったら、次は実際にリクエストを処理する「関数ベースビュー(FBV)の書き方」で、Viewの中身を詳しく見ていきましょう。
タグ: Django, 初心者向け, フレームワーク基礎