Flask の Jinja2 の autoescape について
こんな現象に遭遇したので覚え書き
そもそも
- Flask は テンプレートエンジンにJinja2を採用している。
- テンプレートをレンダリングする時は自動エスケープ(autoescape)される。
エスケープされない
autoescapeという名前から、全てのテンプレートの処理で自動エスケープされると思っていたが、そうじゃなかった。
たとえばこんなケースだ。
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def index(): return render_template('index.tmpl', rawhtml='<a href="http://example.com">hoge</a>') if __name__ == '__main__': app.run()
これをブラウザで出力したとき、rawhtmlは、エスケープされて下記のように出力される事を期待するだろう。
<a href="http://example.com">hoge</a>
ところが、これは期待に反して素のaタグが出力されてしまう。
<a href="http://example.com">hoge</a>
なぜ?
render_templateに渡してるテンプレートファイル名を見てほしい。
index.tmpl
テンプレートファイルになんだか、見慣れない独自の拡張子を使っている。これが原因だ。
テンプレートファイルをリネームして「index.html」に変えて、render_templateの引数を「index.html」に変える。
すると、正しくエスケープされる。
どういうこと?
結論を言うと「autoescape」対象となるテンプレートの拡張子は決まっている。
「flask/app.py」のソースの下記箇所がそれに該当する。
634 def select_jinja_autoescape(self, filename): 635 """Returns `True` if autoescaping should be active for the given 636 template name. 637 638 .. versionadded:: 0.5 639 """ 640 if filename is None: 641 return False 642 return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
「.html」「.htm」「.xml」「.xhtml」しかautoescapeの対象にならないのだ。
- バージョン0.5 からそのような仕様になったらしい
で回避策は?
autoescape対象となる拡張子を追加するには、ソースにベタで拡張子が書いてるのを見ても分かる通り、あまり簡単ではなさそうだ。「.html」なりで統一する事をお勧めします。
けど追加したい、どうしても追加したい、という言う人は、下記のように強引に変える手もあるが、ものすごくバッドノウハウ臭がするのでオススメしません。
def select_jinja_autoescape(filename): """ jinja2のautoescape対象の判別メソッドを差し替える :refs: Flask.select_jinja_autoescape """ if filename is None: return False return filename.endswith(('.html', '.htm', '.xml', '.xhtml', '.tmpl')) app.jinja_env.autoescape = select_jinja_autoescape
ちなみに
- autoescapeが効いているテンプレート上で、部分的にautoescapeを止めたい時には下記のようにすればよい
{% autoescape false %} {{ rawhtml }} {% endautoescape %}