前回(CSSとJavaScriptを読み込む)までは、表示する内容をHTMLに直接書いていました。今回はPython側で用意した値をHTMLに埋め込んで表示します。これができると、データベースの中身やログインユーザー名など「動的な値」をページに出せるようになります。
ポイント:Jinja2のテンプレート記法
Flaskは Jinja2 というテンプレートエンジンを内蔵しています。HTMLの中で次の2つの記法が使えます。
| 記法 | 用途 | 例 |
|---|---|---|
{{ 変数 }} |
値をその場に表示する | {{ name }} |
{% 文 %} |
ループや条件などの制御 | {% for x in list %} |
そして値は、render_template にキーワード引数として渡します。
補足:Jinja2は個別インストール不要
入門記事によっては「まず pip install Jinja2 する」という手順が載っていることがありますが、Flaskを入れていればこの手順は不要です。Jinja2はFlaskの依存ライブラリとして、Flaskのインストール時に自動で一緒に入ります。
$ pip show jinja2
Name: Jinja2
Version: 3.1.6
Required-by: Flask # ← Flaskが必要としているので自動で入っている
pip install Flask(= requirements.txt に Flask と書く)だけで、Flaskが動くのに必要な Jinja2・Werkzeug・click などがまとめて入ります。これを依存関係の自動解決と呼びます。なので requirements.txt にわざわざ Jinja2 を書き足す必要はありません。
コード
代表的な4つの型(文字列・リスト・辞書・真偽値)を渡して、それぞれの扱い方を一通り見てみます。
app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
# Pythonの代表的な4つの型をHTMLに渡してみる
s = "abc" # 文字列
lis = ["a1", "a2", "a3"] # リスト(配列)
dic = {"name": "John", "age": 24} # 辞書(キーと値のペア)
bl = True # 真偽値(True / False)
# キーワード引数でテンプレートに渡す
return render_template("index.html", s=s, lis=lis, dic=dic, bl=bl)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
render_template("index.html", s=s, ...) の s= の左側がHTML側で使う名前、右側がPythonの変数です。
templates/index.html
型ごとに表示の仕方が少しずつ違います。<hr> で区切って4つを順に並べています。
{# 文字列:そのまま {{ }} で表示 #}
<p>{{ s }}</p>
<hr>
{# リスト:for で1件ずつ取り出して表示 #}
<ul>
{% for x in lis %}
<li>{{ x }}</li>
{% endfor %}
</ul>
<hr>
{# 辞書:キーで値を取り出す(Pythonの % 書式でまとめて表示) #}
<p>{{ "name: %s age: %s" % (dic["name"], dic["age"]) }}</p>
<hr>
{# 真偽値:if / else で表示を切り替える #}
{% if bl %}
<p>True</p>
{% else %}
<p>False</p>
{% endif %}
型ごとのポイントをまとめると次のとおりです。
| 型 | 取り出し方 |
|---|---|
| 文字列 |
{{ s }} でそのまま表示 |
| リスト |
{% for x in lis %} で1件ずつ表示 |
| 辞書 |
dic["name"] のようにキーで取り出す |
| 真偽値 |
{% if bl %} 〜 {% else %} で切り替え |
ハマりどころ:HTMLコメントの中にJinja記法を書かない
説明のつもりで HTMLコメント <!-- {{ }} の説明 --> のように書くと、次のエラーで500になります。
jinja2.exceptions.TemplateSyntaxError: Expected an expression, got 'end of print statement'
これは、HTMLコメント <!-- --> はJinjaには効かないため。Jinjaはコメントの中身まで読み、空の {{ }} を「中身のない変数」と解釈してエラーになります。
解説コメントを書きたいときは、Jinja専用のコメント {# ... #} を使います。こちらは出力にも出ず、中の {{ }} も評価されません。
実行と確認
$ curl -s http://localhost:5000/ | grep -E "<p>|<li>"
<p>abc</p>
<li>a1</li>
<li>a2</li>
<li>a3</li>
<p>name: John age: 24</p>
<p>True</p>
文字列・リスト・辞書・真偽値のすべてが、それぞれの記法どおりにHTMLへ埋め込まれているのがわかります。
まとめ
-
{{ 変数 }}で値を表示、{% 文 %}でループ・条件 - 値は
render_template("xxx.html", キー=値)で渡す - 文字列・リスト・辞書・真偽値の4型を一通り埋め込めるようにした(リストは
for、辞書はキー指定、真偽値はif/else) - HTMLコメントの中にJinja記法を書くとエラー → 解説には
{# #}を使う - 次回はGET/POSTでブラウザからFlaskへ値を渡す予定