Flask の Blueprint は、ルート、静的ファイル、テンプレートをまとめて管理できます。しかし、テンプレートが指定できません。
ここでは、Blueprint の template_folder の問題点と回避策を説明します。
Blueprint のテンプレート問題
一般的な Blueprint の定義は次のようになります。
この設定で期待されるのは
この Blueprint は
templates/tags/内のテンプレートを使用するrender_template("list.html")を呼び出すと、templates/tags/list.htmlが読み込まれる
ところが Blueprint ではテンプレートが指定できません。
どうなるかというと
Flask は Blueprint ごとにテンプレートを分離しません。 すべての Blueprint のテンプレートディレクトリを 一つの検索パスに統合します。
Flask のテンプレート検索は次のように行われます。
すべての Blueprint の
template_folderを収集グローバルな
templates/ディレクトリを追加それらを一つのリストにまとめる
ファイル名だけで検索する
最初に見つかったファイルを採用する
このため、同じ名前のテンプレートがあると衝突します。
Blueprint の登録順によっては /tags にアクセスしても words/list.html が読み込まれます。
回避策
1. 名前空間付きパスを使用する
Blueprint の template_folder を使わず、次のように明示します。
2. テンプレート名をユニークにする
Blueprint ごとにファイル名を変える方法です。 規模が大きくなると管理が難しくなります。
3. 独自の Jinja 環境を使用する(完全分離)
Blueprint ごとに独立したテンプレートローダーを作成します。
この方法は Flask のテンプレートローダーを完全に回避できますが、 CSRF などの Flask コンテキストを手動で注入する必要があります。
結論
方法3でハマりました。これだと Flask の正規なルートを通らないのでエラーが出ます(CSRFトークンがないとか)。方法1が無難です。定数を設定して回避する古典的な手法がおすすめです。