URL ディスパッチャ

すっきりした、簡潔で明解な URL スキームは、高品質な Web アプリケーションでは重要な要素です。 Django では、フレームワークの制限なしに、望み通りの URL を設計できます。

URL はすっきりした扱いやすいものにすべきであるという主張については、ワール ドワイドウェブの産みの親である Tim Berners-Lee の優れた解説、 Cool URIs don't change を参照してください。

概要

アプリケーションのURLを設計するには、俗に URLconf (URL configuration) と呼ばれる Python モジュールを作る必要があります。このモジュールは pure Python コードであり、URLパス表記とあなたの書いたビューの Python 関数とのマッピングです。

このマッピングは短くもできますし、必要なだけ長くもできます。他のマッピングも参照できます。また、pure Python コードなので、動的に生成できます。

Django は有効にされている言語に従って URL を翻訳するための手段も提供しています。詳しくは 国際化のドキュメント を参照してください。

Django のリクエスト処理

ユーザが Django で作られたサイト上のページをリクエストした時に、どの Python コードが実行されるかは以下のアルゴリズムで決定されます。

  1. まず、Django は、どのモジュールをルート URLconf として使うか決定します。通常は、この値は ROOT_URLCONF に設定されています。ただし、 HttpRequest オブジェクトに urlconf という属性が設定されていた場合 ( middleware で設定されます) 、その値を ROOT_URLCONF の代わりに使います。
  2. Django はその Python モジュールをロードして、urlpatterns という名前の変数を探します。この変数の値は django.urls.path() または django.urls.re_path() インスタンスの sequence でなければなりません。
  3. Django は URL パターンを順に調べて、 path_info にマッチする、リクエストされた URL にマッチする最初のパターンで停止します。
  4. ある 1 個の正規表現にマッチしたら、 Django はマッピングで指定されたビューを import して呼び出します。そのビューは Python 関数 (もしくは クラスベースのビュー) です。ビューには以下の引数が渡されます:
    • HttpRequest のインスタンス。
    • マッチしたURLパターンに名前付きグループが含まれていない場合、正規表現でマッチした値が位置引数として提供されます。
    • 指定された URL パス表現でマッチした名前付き部分からはキーワード引数が作られます。ただし、 django.urls.path()django.urls.re_path()kwargs オプション引数が指定されていた場合は、その中の引数で上書きされます。
  5. もし、 URL 正規表現が何にもマッチしなかったり、パターンマッチングプロセスの途中のどこかで例外が発生した場合、Django は適切なエラーハンドリングビューを呼び出します。下の Error handling を見てください。

カスタマイズ例

URLconf のサンプルです。

from django.urls import path

from . import views

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    path("articles/<int:year>/", views.year_archive),
    path("articles/<int:year>/<int:month>/", views.month_archive),
    path("articles/<int:year>/<int:month>/<slug:slug>/", views.article_detail),
]

メモ:

  • URLから値をキャプチャするには、角括弧を使用します。
  • 取り込んだ値にはオプションでコンバータタイプを含めることができます。たとえば、整数のパラメータをキャプチャするには <int:name> を使用します。コンバータが含まれていない場合は、 / 文字を除いた文字列がマッチします。
  • スラッシュを先頭につける必要はありません。たとえば、 /articles ではなく articles です。

リクエストの例:

  • articles/2005/03/ へのリクエストはリストの 3 番目のエントリにマッチします。Django は関数 views.month_archive(request, year=2005, month=3) を呼び出します。
  • /articles/2003/ はリストの最初のパターンにマッチしますが、2番目のパターンにはマッチしません。なぜなら、パターンはソート順に検査され、最初のパターンが最初に通るからです。ソートを利用して、このような特殊なケースを挿入するのは自由です。ここでは、 Django は関数 views.special_case_2003(request) を呼び出します。
  • 各パターンはURLの末尾がスラッシュであることを要求するので、/articles/2003 はこれらのパターンのどれにもマッチしません。
  • /articles/2003/03/building-a-django-site/ は最後のパターンにマッチします。Django は関数 views.article_detail(request, year=2003, month=3, slug="building-a-django-site") を呼び出します。

パス コンバータ

デフォルトでは、以下のパスコンバータが使用可能です:

  • str - パスの区切り文字 '/ を除く、空でない文字列にマッチします。これは式にコンバータが含まれていない場合のデフォルトです。
  • int - ゼロまたは任意の正の整数にマッチします。 int を返します。
  • slug - ASCII 文字か数字、ハイフン、アンダースコアからなるスラグ文字列にマッチします。たとえば、 building-your-1st-django-site のようなものです。
  • uuid - フォーマットされたUUIDにマッチします。複数のURLが同じページにマッピングされるのを防ぐため、ダッシュを入れ、アルファベットは小文字にする必要があります。たとえば 075194d3-6885-417e-a8a8-6c931e272f00 のようになります。 UUID インスタンスを返します。
  • path - パスの区切り文字 '/' を含む、空ではない文字列にマッチします。これにより、 str のようにURLパスのセグメントではなく、完全なURLパスに対してマッチすることができます。

独自のパスコンバータを登録する

より複雑なマッチング要件については、独自のパスコンバータを定義できます。

コンバーターとは、以下のようなクラスです:

  • 文字列としての regex クラス属性を持ちます。
  • to_python(self, value) メソッドで、マッチした文字列をビュー関数に渡す型に変換します。与えられた値を変換できない場合は ValueError を発生させます。 ValueError はマッチしないと解釈され、別のURLパターンがマッチしない限り、結果として404レスポンスがユーザーに送信されます。
  • to_url(self, value) メソッドで、 Python の型を URL で使用する文字列に変換します。与えられた値を変換できない場合は ValueError を発生させる必要があります。 ValueError はマッチしないと解釈され、結果として reverse()NoReverseMatch を発生させます。

例:

class FourDigitYearConverter:
    regex = "[0-9]{4}"

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

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

register_converter(): を使用して、URLconf にカスタムコンバータクラスを登録します:

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, "yyyy")

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    path("articles/<yyyy:year>/", views.year_archive),
    ...,
]

正規表現を使う

パスとコンバータ構文だけでは URL パターンを定義するのに不十分な場合は、正規表現を使うこともできます。その場合は path() の代わりに re_path() を使ってください。

Python の正規表現では、名前付き正規表現グループの構文は (?P<name>pattern) です。ここで name はグループの名前で、 pattern はマッチするパターンです。

先ほどのURLconfの例を正規表現を使って書き直したものです:

from django.urls import path, re_path

from . import views

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
    re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.month_archive),
    re_path(
        r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$",
        views.article_detail,
    ),
]

これは、前の例とほぼ同じことを実現します:

  • マッチする正確なURLは少し制約があります。たとえば、西暦10000年はマッチしなくなります。西暦の整数は正確に4桁になるように制約されているからです。
  • キャプチャされた各引数は、正規表現がどのようなマッチをするかには関係なく、文字列としてビューに送信されます。

path() を使っていたのを re_path() に切り替えたり、その逆を行ったりする場合は、ビューの引数の型が変わる可能性があることに十分注意してください。

名前なし正規表現グループの使用

名前付きグループ構文、例えば (?P<year>[0-9]{4}) の他に、より短い名前なしグループ、例えば ([0-9]{4}) を使うこともできます。

このような使い方をすると、マッチの意図した意味とビューの引数との対応を間違えやすくなり、バグが混入しやすくなるので、使わないことを強く推奨します。

どちらの場合でも、指定した正規表現内で1つのスタイルだけを使用することを推奨します。両方のスタイルが混在している場合、名前のないグループは無視され、名前のあるグループだけがビュー関数に渡されます。

ネストされた引数

正規表現ではネストされた引数を使うことができ、Django はこれらを解決してビューに渡します。このとき、Django は全ての外側のキャプチャされた引数を埋めようとし、ネストされたキャプチャされた引数を無視します。任意でページ引数を取る以下の URL パターンを考えてみます:

from django.urls import re_path

urlpatterns = [
    re_path(r"^blog/(page-([0-9]+)/)?$", blog_articles),  # bad
    re_path(r"^comments/(?:page-(?P<page_number>[0-9]+)/)?$", comments),  # good
]

両方のパターンでネストされた引数を使っており、解決します: 例えば、 blog/page-2/ は 2 つの潜在的な引数 (page-2/2) で blog_articles と一致する結果となります。comments の 2 番目のパターンは、2 にセットされたキーワード引数 page_numbercomments/page-2/ と一致します。 この例での外部の引数は、キャプチャされない引数 (?:...) です。

blog_articles ビューは一番外側のキャプチャされた引数が解決されるのを必要としますが (この例では page-2/ か引数なし)、comments は引数なしか page_number に対する値のどちらかで解決できます。

ネストされたキャプチャされた引数は、blog_articles (ビューが興味を持つ値だけでなく URL page-2/ の部分を受け取るビュー) によって示されるように、ビュー引数と URL の間に強力な結合を作ります: この結合は、ビューを解決する際にページ番号ではなくURLの部分を渡す必要があるため、解決するときにはさらに顕著になります。

経験則として、正規表現が引数を必要とする一方でビューがそれを無視するときには、ビューが必要とする値だけをキャプチャして、キャプチャしない引数を使ってください。

URLconf の検索対象

URLconf はリクエストされた URL を通常の Python 文字列として検索します。これには GET や POST パラメータ、ドメイン名は含まれません。

たとえば、https://www.example.com/myapp/ へのリクエストでは、URLconf は myapp/ を探します。

https://www.example.com/myapp/?page=3 へのリクエストでは、URLconf は myapp/ を探します。

URLconf はリクエストメソッドを見ません。つまり、すべてのリクエストメソッド (POST, GET, HEAD など) は同じURLの同じ関数にルーティングされます。

ビュー引数のデフォルト値を指定する

便利なテクニックは、ビューの引数にデフォルトのパラメータを指定することです。以下は URLconf とビューの例です:

# URLconf
from django.urls import path

from . import views

urlpatterns = [
    path("blog/", views.page),
    path("blog/page<int:num>/", views.page),
]


# View (in blog/views.py)
def page(request, num=1):
    # Output the appropriate page of blog entries, according to num.
    ...

上記の例では、URLパターンはどちらも同じビュー、 views.page を指していますが、最初のパターンはURLから何も取得していません。最初のパターンにマッチした場合、 page() 関数は num のデフォルト引数である 1 を使用します。2番目のパターンにマッチした場合、 page() はキャプチャされた num の値を使用します。

パフォーマンス

Django は urlpatterns リストにある正規表現を処理します。それ以降のリクエストでは、 URL リゾルバ経由でキャッシュされた設定を使います。

urlpatterns 変数の構文

urlpatternsdjango.urls.path() または django.urls.re_path() インスタンスの sequence でなければなりません。

エラーハンドリング

Django がリクエストされた URL にマッチするものを見つけられなかったり、例外 が発生したりすると、Django はエラーハンドリングビューを起動します。

これらのケースで使用するビューは、4種類の変数で指定します。ほとんどのプロジェクトではデフォルト値で十分ですが、デフォルト値を上書きすることでさらにカスタマイズできます。

詳細は エラービューをカスタマイズする を参照してください。

このような値はルートの URLconf で設定できます。他の URLconf でこれらの変数を設定しても意味はありません。

値は呼び出し可能オブジェクト、つまり、エラー状態を処理するために呼び出すべきビューへの Python インポートパスを表す文字列でなければなりません。

変数の種類は下記です。

他の URLconfs をインクルードする

いずれの時点でも、urlpatterns は他の URLconf モジュールを "含む (インクルードする)" ことができます。これは基本的に、他の URL パターンに定義されている URL のセットを探索します。

例えば、以下は Django website 自体に対する URLconf の引用です。これは複数の他の URLconfs をインクルードしています:

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path("community/", include("aggregator.urls")),
    path("contact/", include("contact.urls")),
    # ... snip ...
]

Django が include() に出会うたびに、そのポイントまでにマッチした URL の部分を切り落とし、残りの文字列を、インクルードされた URLconf へ渡し、次の処理が行われます。

他の方法として、 path() インスタンスのリストを使うことによって追加的な URL をインクルードすることもできます。例えば、以下の URLconf があったとします:

from django.urls import include, path

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    path("reports/", credit_views.report),
    path("reports/<int:id>/", credit_views.report),
    path("charge/", credit_views.charge),
]

urlpatterns = [
    path("", main_views.homepage),
    path("help/", include("apps.help.urls")),
    path("credit/", include(extra_patterns)),
]

この例では、/credit/reports/ という URL は credit_views.report() というビューによって処理されます。

これを使うと、単一のパターンの接頭辞が繰り返し使われるような URLconf の冗長さを回避できます。例えば、以下の URLconf を考えてみます:

from django.urls import path
from . import views

urlpatterns = [
    path("<page_slug>-<page_id>/history/", views.history),
    path("<page_slug>-<page_id>/edit/", views.edit),
    path("<page_slug>-<page_id>/discuss/", views.discuss),
    path("<page_slug>-<page_id>/permissions/", views.permissions),
]

これは、パスの共通部分である接頭辞を一度だけ記述し、異なる接尾辞を以下のようにグループ化することで改善できます:

from django.urls import include, path
from . import views

urlpatterns = [
    path(
        "<page_slug>-<page_id>/",
        include(
            [
                path("history/", views.history),
                path("edit/", views.edit),
                path("discuss/", views.discuss),
                path("permissions/", views.permissions),
            ]
        ),
    ),
]

取り込まれたパラメータ

インクルードされた URLconf は親の URLconf から取り込まれた全てのパラメータを受け取るので、以下の例は有効です:

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path("<username>/blog/", include("foo.urls.blog")),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path("", views.blog.index),
    path("archive/", views.blog.archive),
]

上の例では、取り込まれた "username" 変数はインクルードされたURLconf に渡されます。

追加的なオプションをビュー関数に渡す

URLconfs は、Ptyhon のディクショナリとして、ビュー関数に追加の引数を引き渡せるようにするフックを持っています。

path() 関数はオプションで第3引数を取ることができます。第3引数にはビュー関数に渡す追加のキーワード引数の辞書を指定します。

例:

from django.urls import path
from . import views

urlpatterns = [
    path("blog/<int:year>/", views.year_archive, {"foo": "bar"}),
]

この例では、/blog/2005/ へのリクエストに対して、Django は views.year_archive(request, year=2005, foo='bar') を呼び出します。

このテクニックは 配信フィードフレームワーク で使われ、メタデータとオプションをビューに引き渡します。

競合を解決する

名付けられたキーワード引数をキャプチャする URL パターンを使うこともできます。これは、追加の引数のディクショナリ内と同じ名前の引数を引き渡します。このとき、URL 内でキャプチャされた引数ではなく、ディクショナリ内の引数が使われます。

include() に追加のオプションを引き渡す

同様に、 include() に追加オプションを渡すと、 インクルードされた URLconf の各行に追加オプションが渡されます。

例えば、以下の 2 つの URLconf のセットはまったく同じように機能します:

セット 1:

# main.py
from django.urls import include, path

urlpatterns = [
    path("blog/", include("inner"), {"blog_id": 3}),
]

# inner.py
from django.urls import path
from mysite import views

urlpatterns = [
    path("archive/", views.archive),
    path("about/", views.about),
]

セット 2:

# main.py
from django.urls import include, path
from mysite import views

urlpatterns = [
    path("blog/", include("inner")),
]

# inner.py
from django.urls import path

urlpatterns = [
    path("archive/", views.archive, {"blog_id": 3}),
    path("about/", views.about, {"blog_id": 3}),
]

行のビューが実際にそれらのオプションを有効として受け入れるかどうかに関わらず、追加のオプションが 常に インクルードされている URLconfの すべての 行に引き渡されることに注意してください。 このため、このテクニックは、インクルードされた URLconf のすべてのビューが、引き渡される追加のオプションを受け入れることが確実である場合にのみ役立ちます。

URL の逆引き

Django プロジェクトで作業するときの一般的なニーズとして、生成されたコンテンツ (ビューとアセットのURL、ユーザーに表示されるURLなど) への埋め込み、またはサーバーサイドでのナビゲーションフローの処理 (リダイレクトなど) のどちらかに対して、最終的なフォーム内で URL を取得することが挙げられます。

こうした URL のハードコーディング (手間がかかり、スケールしにくく、誤りが起こりやすい戦略) は、避けることが強く望まれます。 同様に危険なのは、URLconf で記述された設計と並行して URL を生成するような一時的な仕組みを考え出してしまうことです。これは、時間の経過とともに古くて使えない URL が生成されてしまう原因となります。

言い換えると、必要なのはDRYな仕組みです。 数々の利点の中でも、これは URL 設計が進化していけるようにします。プロジェクトソースコードを全て検索して古い URL を置換する必要はありません。

URLを取得するために利用可能な主な情報は、それを扱うビューの識別(例えば名前)です。正しい URL を探し出すために必要な他の情報は、ビューの引数の型 (位置、キーワード) と値です。

Django は URL マッパーが URL 設計の唯一のリポジトリとなるような解決策を提供します。URLconfを入力すると、双方向で使用できます:

  • ユーザ/ブラウザから要求された URL を起点に、URL から抽出した値で必要な引数を与え、適切な Django ビューを呼び出します。
  • Djangoにおいて、特定のビューとそれに渡される引数の値を特定した上で、関連するURLを取得するプロセスが存在します。このプロセスでは、ビューの識別と引数の値をもとに、それに紐づくURLを生成または特定できます。

最初のものは、前のセクションで説明した使い方です。もう1つは、 URLの逆解決逆URLマッチング逆URLルックアップ 、あるいは単に URLの逆引き として知られているものです。

Django は、 URL が必要とされる様々なレイヤにマッチする URL の逆引きを実行するためのツールを提供します:

  • テンプレートでは: url を使います。
  • Pythonコードでは: reverse() 関数を使います。
  • Django モデルインスタンスの URL のハンドリングに関連する、より高レベルのコードでは: get_absolute_url() を使います。

このURLconfのエントリーについてもう一度考えてみましょう:

from django.urls import path

from . import views

urlpatterns = [
    # ...
    path("articles/<int:year>/", views.year_archive, name="news-year-archive"),
    # ...
]

この設計によると、 nnnn 年に対応するアーカイブのURLは /articles/<nnnn>/ です。

これらをテンプレートコードで取得するには、次のようにします:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

または Python コードで次のようにします:

from django.http import HttpResponseRedirect
from django.urls import reverse


def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse("news-year-archive", args=(year,)))

もし何らかの理由で、年間記事アーカイブのコンテンツが公開されるURLを変更することになった場合、URLconfのエントリを変更するだけです。

ビューが一般的なものである場合、URLとビューの間に多対一の関係が存在することがあります。このような場合、 URL を反転させるときに、ビュー名は十分な識別子ではありません。Django が提供する解決策を知るには、次の節を読んでください。

URL パターンに名前をつける

URL のリバースを処理するためには、上述の例で行ったように 名前をつけられた URL パターン を使う必要があります。URL 名として使う文字列には、どんな文字でも含めることができます。Python の有効な名前に制限を受けません。

URL パターンに名前をつけるときは、他のアプリケーションが選んだ名前と衝突しにくい名前を選んでください。URL パターンを comment と命名し、他のアプリケーションが同じことをした場合、 reverse() が見つける URL は、プロジェクトの urlpatterns リストの最後にあるパターンに依存します。

URL名にプレフィックス、例えばアプリケーション名から派生したもの( comment の代わりに myapp-comment など)を付けると、衝突の可能性を減らせます。

ビューをオーバーライドしたい場合、他のアプリケーションと 同じURL名 を意図的に選択できます。たとえば、よくある使用例は LoginView をオーバーライドすることです。Django の一部やほとんどのサードパーティアプリは、このビューが login という名前の URL パターンを持っていると仮定しています。カスタムログインビューがあり、その URL に login という名前をつけている場合、 reverse() は、django.contrib.auth.urls がインクルードされた後の urlpatterns にある限り(すべてを探して含まれていれば)、カスタムビューを見つけます。

引数が異なれば、複数の URL パターンに同じ名前を使うこともできます。URL 名に加えて、 reverse() は引数の数とキーワード引数の名前もマッチします。パスコンバータは、マッチしなかったことを示すために ValueError を発生させることがあります。詳細は 独自のパスコンバータを登録する を参照してください。

URL の名前空間

はじめに

URL名前空間を使用すると、異なるアプリケーションが同じURL名を使用していても、 名前付きURLパターン を一意に逆引きできます。サードパーティアプリは常に名前空間付きのURLを使用することが良い習慣です(チュートリアルで行ったように)。同様に、アプリケーションの複数のインスタンスがデプロイされている場合にURLを逆引きすることも可能にします。言い換えれば、単一のアプリケーションの複数のインスタンスが名前付きURLを共有する場合、名前空間はこれらの名前付きURLを区別する方法を提供します。

URL の名前空間を適切に使用する Django アプリケーションは、特定のサイトに対して何回でもデプロイできます。 たとえば django.contrib.admin には AdminSite クラスがあり、 admin のインスタンスを複数回デプロイ することができます。後者の例では、2 つの異なるユーザー (著者と出版者) に同じ機能を提供できるよう、チュートリアルで扱った polls アプリケーションを例に、2 つの異なる場所にデプロイするという考え方について説明します。

URL の名前空間は 2 つの部分に分かれ、両方とも文字列で表されます:

アプリケーションの名前空間
デプロイされているアプリケーションの名前を示します。 単一のアプリケーションのすべてのインスタンスは、同一のアプリケーション名前空間を持ちます。 例えば、Django の admin アプリケーションには、'admin' という比較的分かりやすいアプリケーション名前空間を持っています。
インスタンスの名前空間
アプリケーションの特定のインスタンスを識別します。 インスタンス名前空間は、プロジェクト全体で一意である必要があります。ただし、インスタンス名前空間は、アプリケーション名前空間と同じにすることができます。これは、アプリケーションのデフォルトインスタンスを指定するために使用されます。 例えば、デフォルトの Django admin インスタンスは 'admin' というインスタンス名前空間を持っています。

名前空間の URL は、 ':' 演算子を使って指定します。 たとえば、admin アプリケーションのメインインデックスページは 'admin:index' で参照されます。 これは 'admin' という名前空間と 'index' という名前の URL を示します。

名前空間はネストすることもできます。 名前付きの URL 'sports:polls:index' は、トップレベルの名前空間 'sports' 内で定義されている名前空間 'polls' 内で 'index' と名前がつけられたパターンを探します。

名前空間の URL を逆引きする

名前空間の URL (例: 'polls:index') が与えられると、Django 完全修飾名をパーツに分割し、以下のルックアップを試みます:

  1. まず最初に、Django は アプリケーションの名前空間 (ここでは 'polls') との一致を検索します。これは、このアプリケーションのインスタンスのリストを生成します。

  2. 現在のアプリケーションが定義されている場合、Django はそのインスタンスに対して URL リゾルバを探し出し、返します。現在のアプリケーションは reverse() 関数への current_app 引数で指定できます。

    url テンプレートタグは、RequestContext 内で現在のアプリケーションとされているビューの名前空間を使います。このデフォルト設定は、request.current_app 属性で現在のアプリケーションを設定することでオーバーライドできます。

  3. 現在のアプリケーションがない場合、Django はデフォルトのアプリケーションインスタンスを探します。デフォルトのアプリケーションインスタンスは、 application namespace と一致する instance namespace を持つインスタンスです。 (ここでは 'polls' と呼ばれる polls のインスタンスです).

  4. デフォルトのアプリケーションインスタンスがない場合、Django は、そのインスタンス名が何であれ、アプリケーションの最後にデプロイされたインスタンスを利用します。

  5. 提供された名前空間がステップ 1 の application namespace と一致しない場合、Django は名前空間のルックアップを instance namespace として直接試みます。

ネストされた名前空間がある場合、これらのステップはビューの名前のみが未解決になるまで名前空間の各パートに対して繰り返されます。その後に、このビュー名は見つかった名前空間内の URL として解決されます。

カスタマイズ例

実際の名前解決戦略を示すため、チュートリアルで扱った polls アプリケーションの 2 つのインスタンスの例を考えてみましょう: 1 つは 'author-polls'、もう 1 つは 'publisher-polls' と名付けられています。polls を作成して表示するときにインスタンス名前空間を考慮するように、そのアプリケーションを拡張したとします。

urls.py
from django.urls import include, path

urlpatterns = [
    path("author-polls/", include("polls.urls", namespace="author-polls")),
    path("publisher-polls/", include("polls.urls", namespace="publisher-polls")),
]
polls/urls.py
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
    path("", views.IndexView.as_view(), name="index"),
    path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ...,
]

この設定を使うことで、以下のルックアップが可能となります:

  • インスタンスの一つが現在参照されている場合(例えば、インスタンス 'author-polls' の詳細ページをレンダリングしている場合) 'polls:index''author-polls' インスタンスのインデックスページを解決します。つまり、以下のどちらも "/author-polls/" という結果になります。

    クラスベースビューのメソッド内:

    reverse("polls:index", current_app=self.request.resolver_match.namespace)
    

    テンプレート内:

    {% url 'polls:index' %}
    
  • 現在のインスタンスがない場合(例えば、サイトの他の場所でページをレンダリングしている場合) 'polls:index'polls の最後に登録されたインスタンスに名前解決されます。デフォルトのインスタンス ('polls' のインスタンス名前空間) がないため、登録された最後の polls のインスタンスが使用されます。これは、urlpatterns で最後に宣言されている 'publisher-polls' になります。

  • 'author-polls:index' は、常に 'author-polls' のインスタンスのインデックスページに名前解決します (そして 'publisher-polls' に対しても同じです) .

デフォルトのインスタンス、つまり 'polls' という名前のインスタンスがある場合、上記からの唯一の変更点は現在のインスタンスがない場合(上記リストの2番目の項目)です。この場合、'polls:index'urlpatterns で最後に宣言されたインスタンスの代わりにデフォルトインスタンスのインデックスページに名前解決されます。

URLの名前空間とインクルードされた URLconfs

インクルードされた URLconfs のアプリケーション名前空間は、2 つの方法で指定できます。

1 つめは、インクルードされた URLconf で app_name 属性をセットする方法で、これは urlpatterns 属性と同じレベルに記述します。urlpatterns のリスト自体ではなく、実際のモジュールないし include() への文字列参照に対して引き渡す必要があります。

polls/urls.py
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
    path("", views.IndexView.as_view(), name="index"),
    path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ...,
]
urls.py
from django.urls import include, path

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

polls.urls 内で定義された URL は、アプリケーション名前空間 polls を持ちます。

2つめは、埋め込みの名前空間データを含むオブジェクトをインクルードする方法です。 path() または re_path() インスタンスのリストを include() する場合、このオブジェクトに含まれる URL はグローバルの名前空間に含まれるようになります。ただし、以下を含む 2値タプルを include() することもできます:

(<list of path()/re_path() instances>, <application namespace>)

例:

from django.urls import include, path

from . import views

polls_patterns = (
    [
        path("", views.IndexView.as_view(), name="index"),
        path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ],
    "polls",
)

urlpatterns = [
    path("polls/", include(polls_patterns)),
]

これは、与えられたアプリケーション名前空間に、指定された URL パターンをインクルードします。

インスタンスの名前空間は、 include()namespace 引数を使うことで指定できます。インスタンス名前空間が指定されていない場合、インクルードされた URLconf のアプリケーション名前空間がデフォルトとなります。つまり、その名前空間のデフォルトインスタンスになります。

Back to Top