pyてよn日記

一寸先は闇が人生

Django:テンプレートの配置と名前空間

 Django では,各アプリケーションごとにテンプレートを置くためのディレクトリを作成する(ここで言うアプリケーションとは「python manage.py startapp [app-name] で作られるパッケージ(ディレクトリ)」のこと).そのディレクトリ構造が少し複雑なのでその仕組みを覚書として残しておく.

 以下,参考にした公式チュートリアルのページ.

docs.djangoproject.com

Django のテンプレートを置くためのディレクトリ構造について

 今,下記のようなディレクトリ構造の Django プロジェクトがあるとする.デフォルトで作られるプロジェクトに,polls という一つのアプリケーションが追加された状態である.

.
├── config
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── polls  # 追加されたアプリケーション
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    ├── models.py
    ├── tests.py
    ├── urls.py
    └── views.py

 Django では,アプリケーションpolls にテンプレートを追加する際には,ディレクトpolls 下に templates というテンプレート用のディレクトリを作ってテンプレートを置くと Django 側で上手く読み込んでくれる.実際には,config/settings.pyINSTALLED_APPS に追加されたアプリケーションの templates サブディレクトリを検索してテンプレートを読み込んでくれる.

 しかし,一つ注意点がある.例えば,index.html というテンプレートを polls アプリケーションに追加する際には,polls/templates/index.html ではなく,polls/templates/polls/index.html というディレクトリ構造でテンプレートを置く必要がある.

  • ダメ:polls/templates/index.html
  • OK:polls/templates/polls/index.html

 これは以下のような理由による.

Template namespacing

Now we might be able to get away with putting our templates directly in polls/templates (rather than creating another polls subdirectory), but it would actually be a bad idea. Django will choose the first template it finds whose name matches, and if you had a template with the same name in a different application, Django would be unable to distinguish between them. We need to be able to point Django at the right one, and the easiest way to ensure this is by namespacing them. That is, by putting those templates inside another directory named for the application itself.

はじめての Django アプリ作成、その 3 | Django ドキュメント | Django より引用

 解釈すると,

  • Django は最初に名前が一致したテンプレートを選択する.
  • 異なるアプリケーションの templates ディレクトリに同じ名前のテンプレートがある場合,それらを区別できない(例えば,index.html は被りやすい).
    • [app1]/templates/index.html[app2]/templates/index.html が区別できないということ.
    • Django はアプリケーションごとの templates ディレクトリを認識するわけではなく,全てのアプリケーションの templates サブディレクトリに置かれているテンプレートを一括で探索する
  • Django に正しいテンプレートを認識させる簡単な方法の一つは,名前空間を与えることである.
    • templates ディレクトリ下にアプリケーションと同じ名前を付けたディレクトリを用意してそこにテンプレートを置けば [app-name]/index.html という名前でアプリケーションごとのテンプレートを認識できるようになる.

 要するに,区別できないなら名前空間与えてそれで Django 側に判断してもらえばええやんという話.polls にテンプレートディレクトリを追加した後のディレクトリは以下のようになる.

.
├── config
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── polls  # 追加されたアプリケーション
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    ├── models.py
    ├── templates  # templates サブディレクトリ
    │   └── polls
    │       └── index.html
    ├── tests.py
    ├── urls.py
    └── views.py

 これで Python の View からテンプレートにアクセスするときは polls/index.html という名前でアクセスできるようになった.

参考

現時点での Django の日本語書籍での決定版的な本.アーキテクチャ周りの話から入ってくれるのでありがたいです.