4.

Django ルーティング (URLconf) 作成完全ガイド

編集
この記事の要点
  • Django のルーティングは urls.pyurlpatterns リスト
  • path("users/", views.user_list, name="users") で URL と View を対応付け
  • URL パラメータ: / /
  • アプリ別 URL を include("app.urls") でネスト
  • ビューやテンプレートからは reverse("users") / {% url %} で逆引き

Django ルーティングの全体像

Django のルーティングは URLconf と呼ばれ、ファイル urls.py に書かれた urlpatterns リストで URL → View の対応を表現します。プロジェクトには最低 2 つの urls.py があるのが一般的:

myproject/
├── manage.py
├── myproject/
│   ├── settings.py
│   ├── urls.py          ← プロジェクトのルート URLconf
│   └── wsgi.py
└── users/
    ├── views.py
    ├── urls.py          ← users アプリの URLconf
    └── models.py

基本: path() の使い方

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

urlpatterns = [
    path('', views.user_list, name='user-list'),
    path('users/', views.user_list, name='users'),
    path('users//', views.user_detail, name='user-detail'),
    path('users/create/', views.user_create, name='user-create'),
    path('users//edit/', views.user_edit, name='user-edit'),
    path('users//delete/', views.user_delete, name='user-delete'),
]

URL パラメータ(コンバータ)

コンバータ正規表現変換結果
str[^/]+str(デフォルト)username
int[0-9]+int123
slug[-a-zA-Z0-9_]+strhello-world
uuidUUID 形式UUID550e8400-e29b...
path.+ (スラッシュ含む)strfiles/sub/dir.jpg
urlpatterns = [
    # 整数 ID
    path('articles//', views.year_archive),
    # → /articles/2026/

    # 複数パラメータ
    path('articles///', views.month_archive),
    # → /articles/2026/05/

    # slug
    path('blog//', views.blog_detail),
    # → /blog/my-first-post/

    # UUID
    path('items//', views.item_by_token),
    # → /items/550e8400-e29b-41d4-a716-446655440000/

    # path(スラッシュを含む)
    path('files//', views.file_browser),
    # → /files/2026/05/photos/cat.jpg/
]

View 側でのパラメータ受け取り

# users/views.py
from django.shortcuts import render, get_object_or_404
from .models import User

def user_detail(request, id):
    # URL の  がそのまま引数に
    user = get_object_or_404(User, pk=id)
    return render(request, 'users/detail.html', {'user': user})

def year_archive(request, year):
    articles = Article.objects.filter(year=year)
    return render(request, 'articles/year.html', {'articles': articles, 'year': year})

def file_browser(request, filepath):
    # path コンバータでスラッシュ含むパスを受け取る
    return render(request, 'files/browse.html', {'path': filepath})

include() でアプリ別の urls.py を統合

# myproject/urls.py (プロジェクトのルート)
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),

    # users アプリの URLconf を /users/ 配下にマウント
    path('users/', include('users.urls')),

    # blog アプリの URLconf を /blog/ 配下にマウント
    path('blog/', include('blog.urls')),

    # ルート / は home アプリへ
    path('', include('home.urls')),
]

users/urls.py で path("", ...) としていれば、結果として /users/ になります。

名前付き URL と namespace

# users/urls.py
app_name = 'users'   # 名前空間

urlpatterns = [
    path('', views.user_list, name='list'),
    path('/', views.user_detail, name='detail'),
]

# 参照側
# templates/users/list.html
# 詳細

# views.py
from django.urls import reverse
url = reverse('users:detail', kwargs={'id': 42})
# → "/users/42/"

from django.shortcuts import redirect
return redirect('users:list')

re_path: 正規表現ルート

より複雑なパターンが必要な場合は re_path を使います:

from django.urls import re_path

urlpatterns = [
    # 年月(前ゼロ必須)
    re_path(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$',
            views.month_archive),

    # 大文字英字のみのスラッグ
    re_path(r'^code/(?P[A-Z]+)/$', views.code_view),

    # /old/path/ を /new-path/ にリダイレクト
    re_path(r'^old/(?P.+)/$', views.legacy_redirect),
]

クエリパラメータ(?key=value)

?page=2&sort=name のようなクエリ文字列は URLconf には書かず、View で取得:

# views.py
def user_list(request):
    # URL: /users/?page=2&sort=name
    page = request.GET.get('page', 1)
    sort = request.GET.get('sort', 'id')

    users = User.objects.order_by(sort)
    return render(request, 'users/list.html', {
        'users': users[(int(page)-1)*20: int(page)*20],
        'page': page,
    })

APPEND_SLASH 設定

Django はデフォルトで URL の末尾スラッシュがない場合、付けてリダイレクトします:

# settings.py(デフォルト)
APPEND_SLASH = True
# /users → /users/ に 301 リダイレクト

APPEND_SLASH = False
# /users → 404

カスタム 404 / 500 ハンドラ

# myproject/urls.py
handler404 = 'myproject.views.custom_404'
handler500 = 'myproject.views.custom_500'

# myproject/views.py
from django.shortcuts import render

def custom_404(request, exception):
    return render(request, '404.html', status=404)

def custom_500(request):
    return render(request, '500.html', status=500)

# 注意: DEBUG = False のときのみ有効

URL のテスト

# tests.py
from django.test import TestCase
from django.urls import reverse

class UserURLTest(TestCase):
    def test_user_detail_url(self):
        url = reverse('users:detail', kwargs={'id': 42})
        self.assertEqual(url, '/users/42/')

    def test_user_detail_view(self):
        response = self.client.get('/users/42/')
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'users/detail.html')

    def test_404(self):
        response = self.client.get('/users/99999/')
        self.assertEqual(response.status_code, 404)

カスタムコンバータ

# converters.py
class FourDigitYearConverter:
    regex = '[0-9]{4}'

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return '%04d' % value

# urls.py
from django.urls import path, register_converter
from . import converters, views

register_converter(converters.FourDigitYearConverter, 'yyyy')

urlpatterns = [
    path('articles//', views.year_archive),
]

FAQ

Q: NoReverseMatch エラー
A: {% url %}reverse に渡す名前が urls.py の name= と一致しているか、kwargs が足りているか確認。

Q: URL の末尾スラッシュが厄介
A: Django は / 終わりが慣習。フロントエンド (React/Vue) と齟齬が出る場合は APPEND_SLASH = False + 明示記述で揃える。

Q: re_path と path はどちらを使うべき
A: 通常は path(読みやすい)。正規表現が必要な複雑なケースだけ re_path

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. ビュー(View)
  2. テンプレート(Template)
  3. モデル(Model)
  4. ルーティングの作成
  5. viewからtemplateへの遷移方法