Djangoの名前空間 [name], [namespace], [app_name] の違いについて

はじめに

以下ソースコードの記述例は執筆時において主流である Django1.11 でのものとなっています。 先日 Django2.0 がリリースとなりURLまわりの書き方が変更となりましたが、名前空間の扱いには変わりが無いと認識しています。

役割の違い

nameとはURLパターンに付ける名前

url(r'^$', views.IndexView.as_view(), name='index')

テンプレートから {% url 'index' %}
ビューからreverse('index') のように逆引きで参照できます。

namespace = includeする側の urls.py で指定するプロジェクトにおける名前空間

url(r'^polls/', include('polls.urls', namespace='polls'))

テンプレートから {% url 'polls:index' %} ビューからreverse('polls:index') のように参照できます。
上記では polls/ 配下のURLは "polls" という名前空間になります。

app_name = includeされたアプリ側の urls.py で指定するプロジェクトにおける名前空間

app_name = 'polls'
urlpatterns = [
...
]

テンプレートから {% url 'polls:index' %} ビューからreverse('polls:index') のように参照できる。
上記の urlpatterns に書かれたパスは "polls" という名前空間になります。

こうすることで後々URLが変更になった場合などに修正が容易になります。 こうしてみると namespace と app_name は同じ機能であるようですが、名前空間の指定方法が2種類あるのはなぜか?

調べてみた

どうやら、Django1.9になった際に元々あったnamespaceに対しapp_nameの記法が追加されたよう。

Django 1.9 release notes | Django documentation | Django

The app_name argument to include() has been replaced by passing a 2-tuple (as above), or passing an object or module with an app_name attribute (as below). If the app_name is set in this new way, the namespace argument is no longer required. It will default to the value of app_name.

上記の例と同様ですが、公式ドキュメントの例でいうと
〜Django1.8:
mysite/urls.py

urlpatterns = [
    url(r'^polls/', include('polls.urls', namespace="polls")),
    ...
]

Django1.9〜:
mysite/urls.py

urlpatterns = [
    url(r'^polls/', include('polls.urls')),  # 'namespace="polls"' removed
    ...
]

polls/urls.py

app_name = 'polls'  # added
urlpatterns = [...]

さらに

とあります。これについては下記のようになります。

アプリケーションの名前空間

デプロイされているアプリケーションの名前を示します。 単一のアプリケーションのすべてのインスタンスは、同一のアプリケーション名前空間を持ちます。

インスタンス名前空間

アプリケーションの特定のインスタンスを識別します。 インスタンス名前空間は、プロジェクト全体で一意である必要があります。ただし、インスタンス名前空間は、アプリケーション名前空間と同じにすることができます。これは、アプリケーションのデフォルトインスタンスを指定するために使用されます。

名前空間のURLが与えられると、下記のルックアップを試みます。

  1. アプリケーションの名前空間との一致を検索する
  2. 現在のアプリケーションが定義されていれば、そのインスタンスに対しURL解決をする
  3. 現在のアプリケーションがない場合、デフォルトのアプリケーションインスタンスを探す
  4. デフォルトのアプリケーションインスタンスがない場合、アプリケーションの最後にデプロイされたインスタンスを利用する
  5. 提供された名前空間がステップ 1 のアプリケーション名前空間と一致しない場合、インスタンス名前空間のルックアップを試みる

あとがき

Djangoをやるなら必読の「Two Scoops of Django」の1.11版が出ています。
英語アレルギーがない方はぜひ。

Two Scoops of Django 1.11: Best Practices for the Django Web Framework (English Edition)

Two Scoops of Django 1.11: Best Practices for the Django Web Framework (English Edition)