Flask には Blueprintというアプリケーションをモジュール化出来る機能が備わっていますが、このBlueprintのtemplate_folderパス解決にはちょっとした罠があります。
Flaskで以下のようなパッケージ構成を組んだと仮定します。
run.py
admin/
__init__.py
views.py
pages/
index.html
frontend/
__init__.py
views.py
pages/
index.html
admin/views.py
from flask import Blueprint, render_template
admin = Blueprint('admin', __name__, template_folder='pages')
@admin.route('/')
def index():
return render_template('index.html')
frontend/views.py
from flask import Blueprint, render_template
frontend = Blueprint('frontend', __name__, template_folder='pages')
@frontend.route('/')
def index():
return render_template('index.html')
run.py
app = Flask(__name__)
from admin.views import admin
app.register_blueprint(admin)
from frontend.views import frontend
app.register_blueprint(frontend)
一見template folder
として admin/views.py
では admin/pages/
を 、
frontend/views.py
ではfrontend/pages/
を参照するように読めます。
しかしこのコードは正常に動作しません。
admin/views.py
と frontend/views.py
で template_folder
が、admin/pages/
になるか 、 frontend/pages/
になるかは不定となります。
Flask Blueprintのマニュアルを参照してみると以下のように記述があります。
http://flask.pocoo.org/docs/0.10/blueprints/
So if you have a blueprint in the folder yourapplication/admin and you want to render the template 'admin/index.html' and
you have provided templates as a template_folder you will have to create a file like this: yourapplication/admin/templates/admin/index.html.
つまり、以下のようなパッケージ構成にする必要があるということです。
run.py
admin/
__init__.py
views.py
pages/
admin/
index.html
frontend/
__init__.py
views.py
pages/
frontend/
index.html
admin/views.py
from flask import Blueprint, render_template
admin = Blueprint('admin', __name__, template_folder='pages')
@admin.route('/')
def index():
return render_template('admin/index.html')
frontend/views.py
from flask import Blueprint, render_template
frontend = Blueprint('frontend', __name__, template_folder='pages')
@frontend.route('/')
def index():
return render_template('frontend/index.html')
この仕様は度々Flaskの利用者に誤解を与えてきたようで、以下のように Issueでも議論にもなりました。
Blueprint template lookup not documented enough · Issue #266 · pallets/flask · GitHub
なぜこのような仕様になっているかというと、実装上の都合です。
Flaskで指定するtemplate_folderは Jinja2 の
FileSystemLoader
のsearchpathに渡されます。
searchpathはアプリケーションのトップレベルに追加され、再帰的に検索されるため、template_folderで指定したディレクトリ文字列がかぶっているとどのテンプレートを選択すれば良いのか一意に特定出来ません。
そのため、このような仕様になっています。