DjangoでTemplateDoesNotExistと言われたら
別のブログ記事用に、Djangoで簡単なアプリを作った。モデルがなく、単にView関数を呼び出してTemplateを出すだけ。
from django.shortcuts import render from django.views.generic import View # Create your views here. class IndexView(View): def get(self, request, *args, **kwargs): return render(request, 'myapp/index.html')
するとエラーが出た。
django.template.exceptions.TemplateDoesNotExist: myapp/index.html
このとき何をチェックすべきだろうか。
Templateのパスを確認する
自分がよく間違えるのが、Templateのパスの書き方。
公式ドキュメントを読んで、DjangoのTemplateの探し方を理解しておく必要がある。
Templateの探し方は、プロジェクトのsettings.pyの中にあるTEMPLATES
の項目で規定されている。
デフォルトでは、プロジェクトを作ったあとは以下のような状態になっているはず。(Django2.1の場合)
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', ], }, }, ]
DIRS
に何も入っておらず、APP_DIRS
がTrueになっているので、Djangoはプロジェクト内の各アプリケーションの配下にあるtemplates
という名前のディレクトリ内を探索する。
そのため、単にアプリケーション配下にTemplateファイルを置いてもだめ。templates
というディレクトリを作る必要がある。
各アプリケーションのtemplates
ディレクトリが探索の起点となるので、myapp/templates/myapp/index.html
に置いたTemplateファイルをViewの中で指定するには、単にmyapp/index.html
と書けばよい。
なお、探索の際はどのアプリケーションかを考慮せずに、最初にパスがマッチしたら探索終了となる仕様になっている。そのため、templates
内にさらにディレクトリを切るなどして、名前空間を分けることが推奨されている。
ただ、今回の場合はmyapp/templates/myapp/index.html
となるようにファイルを作っていたので、パスの問題ではなかった。
INSTALLED_APPSを確認する
上記のTemplate探索にはもうひとつ前提がある。「各アプリケーションの配下にあるtemplates
ディレクトリ」を探索するということは、アプリケーションと認識されていなければ探索されないということだ。
今回はそもそもここに原因があった。settings.pyのINSTALLED_APPS
にmyappを登録するのを忘れていた。
INSTALLED_APPS
には、そのプロジェクト内の全てのアプリケーションを登録しなければならない。
アプリケーションがあるパッケージ名をそのまま書いても動くことは動くが、推奨されているのは各アプリケーションのConfigurationクラスを登録することだ。
今回の場合、myapp.apps.MyappConfig
を登録することで、無事にTemplateが表示されるようになった。