アプリケーションディレクトリにテンプレート用ディレクトリを作成して、アプリケーション単位でテンプレートを管理する方法をネットで調べました。 しかし、思うようなものが見つからなかったので、個人的にいろいろと試してみました。 このページのその試した結果をまとめたものです。

このページでは、以下のようなプロジェクト名やアプリケーション名とします。

  • プロジェクト名: mysite
  • アプリケーション名: app
  • テンプレート用ディレクトリ名: templates
プロジェクトがあるディレクトリは、/vagrant/www/mysite になる場合、テンプレートディレクトリの絶対パスは以下になります。
/vagrant/www/mysite/app/templates

テンプレートファイル名が "index.html" の場合、絶対パスは以下になります。

/vagrant/www/mysite/app/templates/index.html
また、別のアプリケーションwordsのテンプレートも同じように用意します。
/vagrant/www/mysite/words/templates/index.html

絶対パスでテンプレートファイルを指定

テンプレートファイルは絶対パスを指定することが可能です。 絶対パスで指定する場合、settings.pyのTEMPLATESはデフォルトのままで大丈夫です。

pathlibモジュール

pathlibモジュールと __file__を使って、アプリケーションディレクトリの絶対パスを取得します。 それをもとにテンプレートファイルの絶対パスを指定します。

例 mysite/app/view.py

from django.shortcuts import render
from pathlib import Path

# Create your views here.
def index(request):
    tpl = Path.joinpath(Path(__file__).parent, 'templates').joinpath('index.html')
    return render(request, tpl)

指定が複数ある場合、テンプレートディレクトリを以下のように定義すると便利です。

tpl_dir = Path.joinpath(Path(__file__).parent, 'templates')

例 mysite/app/view.py

from django.shortcuts import render
from pathlib import Path

tpl_dir = Path.joinpath(Path(__file__).parent, 'templates')

# Create your views here.
def index(request):
    return render(request, tpl_dir.joinpath('index.html'))

osモジュール

osモジュールと __file__を使って、アプリケーションディレクトリの絶対パスを取得します。 それをもとにテンプレートファイルの絶対パスを指定します。

ただし、osモジュールを使うとパス取得が長くるので、アプリケーションディレクトリをAPP_DIR、テンプレートディレクトリをTPL_DIRとして定義しています。

例 mysite/app/view.py

from django.shortcuts import render
import os

APP_DIR = os.path.dirname(os.path.abspath(__file__))
TPL_DIR = os.path.join(os.path.join(APP_DIR, os.path.join('templates')), '')

# Create your views here.
def index(request):
    return render(request,  TPL_DIR + 'index.html')
注意 TPL_DIRは最後にパス区切り文字を付けているので、APP_DIRとTPL_DIRは以下のようになります。
APP_DIR = "/vagrant/www/mysite/app"
TMP_DIR = "/vagrant/www/mysite/app/templates/"

相対パスでテンプレートファイルを指定

相対パスを使う場合、settings.pyの TEMPLATES DIRSの指定が必要です。 ここでは空文字を指定して、プロジェクトディレクトリがテンプレートのトップディレクトリにします。 ビューではアプリケーションディレクトリからの相対パスを指定します。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [''],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

空文字でなくBASE_DIRを指定する方法もあります。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

アプリケーション名を直接指定

テンプレートの数が少ない場合、直接アプリケーション名を指定するのが簡単です。

例 mysite/app/view.py

from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, 'app/templates/index.html')

アプリケーション名をrequestから取得

アプリケーション名変更の可能性がある場合など、汎用性を求める場合はアプリケーション名を自動取得するようにします。 もっと良い方法があると思いますが見つからなかったので、ここではrequest.resolver_match.routeを使った方法になります。

request.resolver_match.routeはURLのパスを取得できますので、それをアプリケーション名に使用します。 アクセスURLが"http://example.com/app/"の場合、request.resolver_match.route は "app/" になります。 これを使って以下のように指定すると、アプリケーションディレクトリが先頭の相対パスが指定できます。

request.resolver_match.route + '[テンプレート名]/[テンプレートファイル名]

例 mysite/app/templates/view.py

from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, request.resolver_match.route + 'templates/index.html'')
参考 上記のテンプレート指定は 'app/templates/index.html' となります。