Django で「TemplateDoesNotExist」が出てテンプレートを読み込めない
TemplateDoesNotExist は、テンプレート名がどの探索先にも見つからないときに出る。
エラー画面の「Template-loader postmortem」に探したパスが並ぶので、DIRS・APP_DIRS・INSTALLED_APPS と配置を突き合わせる。
公開:
要約
Django のテンプレートは、settings.py の TEMPLATES に書いた探索先を順に調べて見つける。
どこにも無ければ次の例外になる。
django.template.exceptions.TemplateDoesNotExist: index.htmlDEBUG = True ならエラー画面に「Template-loader postmortem」が表示され、ローダーごとに実際に探したパスと Source does not exist が並ぶ。
置いたつもりの場所がこの一覧に無ければ、探索先の設定が足りない。
一覧にあるのに見つからなければ、ファイル名かディレクトリの階層が違う。
よくある原因
DIRSが空:startprojectが作る設定は"DIRS": []なので、プロジェクト直下にtemplates/を作っただけでは探索されない。- アプリのディレクトリが探索対象外:
APP_DIRSがTrueのとき、Django はINSTALLED_APPSに登録された各アプリのtemplatesサブディレクトリを探す。
アプリが未登録、またはAPP_DIRSがFalseだとそこは見られない。 - 名前空間の階層が合っていない:
render()に渡す名前は、探索先ディレクトリからの相対パスだ。blog/templates/index.htmlに置いたファイルは"index.html"で見つかり、"blog/index.html"では見つからない。 - 継承元や部品が無い:
{% extends "base.html" %}のbase.htmlが無い場合、例外に出る名前はrender()に渡した名前ではなくbase.htmlになる。
解決策
1. プロジェクト共通のディレクトリを DIRS に登録する
# settings.py
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
# startproject が生成した context_processors はそのまま残す
},
},
]BASE_DIR は startproject が settings.py の先頭で定義しており、manage.py のあるディレクトリを指す。
2. アプリを登録し APP_DIRS を有効にする
アプリ内のテンプレートを使うなら、アプリを INSTALLED_APPS に入れ、APP_DIRS を True にする。
INSTALLED_APPS = [
"blog.apps.BlogConfig",
# ...
]3. アプリ名のサブディレクトリで名前空間を切る
公式ドキュメントは、テンプレートをアプリごとのサブディレクトリに整理する方法を推奨している。
blog/
└── templates/
└── blog/
└── index.htmlfrom django.shortcuts import render
def index(request):
return render(request, "blog/index.html")名前空間を切らずに複数のアプリへ同じ index.html を置くと、INSTALLED_APPS で先に並んだアプリのものが使われる。
エラーにならないまま別のテンプレートが表示されるので、最初から階層を分けておく。
4. 例外に出ている名前を読む
例外やエラー画面の見出しに出ているテンプレート名が、ビューで指定した名前と違うかを確認する。
違うなら、そのテンプレートを {% extends %} か {% include %} している箇所が原因だ。
{% extends "base.html" %}継承元を templates/base.html に置くか、実際の配置に合わせて "layouts/base.html" のように名前を直す。