こんにちは、データサイエンティストのたぬ(@tanuhack)です。
Pythonの軽量フレームワーク『Flask』のテンプレートエンジンと言えばjinja2ですね!
シンプルで簡単にコードが書けるのがjinja2の良いところなのですが、公式リファレンスが英語なのと、見返すのが面倒なので、自分へのメモがてらjinja2の記法チートシートなるものを作成してみました。
目次
render_template関数
HTMLを読み込む
Flaskパッケージのrender_template
関数を使って、簡単にHTMLファイルを読み込むことができます。
その際、読み込みたいHTMLファイルは、templatesフォルダの中に必ず格納しなければなりません。以下のディレクトリを参考にしてください。
『jinja2_test』という作業フォルダを作成して、PythonとHTMLファイルを格納します。
├ app.py
└ templates/
└ index.html
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>HTMLファイルを読み込む</title>
</head>
<body>
<h1>render_template関数</h1>
<p>HTMLファイルは、無事読み込まれています。</p>
</body>
</html>
CSSを読み込む
FlaskでCSSやJavaScript、IMAGEファイルを読み込みたい場合は、以下のディレクトリのようにstaticフォルダを作成し、その中に該当ファイル(※今回はCSSファイル)を格納します。
├ app.py
├ templates/
│ └ index.html
└ static/
└ style.css
CSSファイルを読み込む際に気をつけるポイントは、app.pyのrender_template
関数でHTMLファイルをレンダリングしているので、index.htmlでCSSファイルを読み込むの方法は、app.pyから見たディレクトリを指定します。
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>HTMLファイルを読み込む</title>
<!-- OK -->
<link rel="stylesheet" href="/static/style.css">
<!-- NG -->
<!-- <link rel="stylesheet" href="../static/style.css"> -->
</head>
<body>
<h1>render_template関数</h1>
<p>HTMLファイルは、無事読み込まれています。</p>
</body>
</html>
body {
background: #F4E7D3;
}
h1 {
color: #B01335;
}
p {
color: #1F4E5F;
}
テンプレート継承
各HTMLページで共通する部分は、1つのHTMLファイル(※今回はlayout.html)に記述して、それを継承することができます。
具体的には、個別ページで{% extends "layout.html" %}
と先頭行に記述し、共通ページを継承します。
├ app.py
├ templates/
│ ├ index.html
│ └ layout.html
└ static/
└ style.css
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>HTMLファイルを読み込む</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
{% block content %}
<!-- ここに個別部分が挿入される -->
{% endblock %}
</body>
</html>
{% extends "layout.html" %}
{% block content %}
<h1>テンプレート継承</h1>
<p>index.htmlは、layout.htmlを継承しています。</p>
{% endblock %}
body {
background: #F4E7D3;
}
h1 {
color: #B01335;
}
p {
color: #1F4E5F;
}
変数取得
この章では、サーバーサイド(Python)からクライアントサイド(HTML)に値を渡す方法を紹介します。
具体的には、render_template
関数に引数を設定することで、値(文字列、リスト、辞書など)を渡すことができます。
文字列
クライアントサイドで文字列を受け取る場合、{{ hoge }}
のように、サーバーサイドで設定した引数と同じ値を{{ }}
の中に記述します。
├ app.py
└ templates/
└ index.html
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
title = 'indexページ'
message = 'ここにはメッセージが入ります。ここにはメッセージが入ります。'
return render_template('index.html', title=title, message=message)
if __name__ == '__main__':
app.run(debug=True)
この例では、titleとmessage変数にそれぞれ文字列を格納し、クライアントサイドに文字列を渡しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{{ title }}</title>
</head>
<body>
<p>{{ message }}</p>
</body>
</html>
リスト
├ app.py
└ templates/
└ index.html
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
shikoku_list = ['愛媛県', '高知県', '徳島県', '香川県']
return render_template('index.html', shikoku=shikoku_list)
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>リストを渡す</title>
</head>
<body>
<p>{{ shikoku[0] }}</p>
<p>{{ shikoku[1] }}</p>
<p>{{ shikoku[2] }}</p>
<p>{{ shikoku[3] }}</p>
</body>
</html>
辞書型配列
├ app.py
└ templates/
└ index.html
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
fruit_dict = {'orange':100, 'apple':200}
return render_template('index.html', fruit=fruit_dict)
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>辞書型配列を渡す</title>
</head>
<body>
<p>オレンジ:{{ fruit.orange }}</p>
<p>りんご:{{ fruit.apple }}</p>
</body>
</html>
制御構文
if文
├ app.py
└ templates/
└ index.html
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', num=1)
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>制御構文|if文</title>
</head>
<body>
{% if num==0 %}
<p>変数numには0が格納されている</p>
{% elif num==1 %}
<p>変数numには1が格納されている</p>
{% else %}
<p>それ以外</p>
{% endif %}
</body>
</html>
for文
├ app.py
└ templates/
└ index.html
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
shikoku_list = ['愛媛県', '高知県', '徳島県', '香川県']
return render_template('index.html', shikoku=shikoku_list)
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>制御構文|for文</title>
</head>
<body>
{% for i in shikoku %}
{{ i }}
{% endfor %}
</body>
</html>
requestモジュールと組み合わせる
HTMLのFormタグでユーザーから受け取った値をPythonでごにゃごにゃした後、再度クライアントサイドに返す方法を紹介します。
├ app.py
├ templates/
│ ├ input.html
│ ├ output.html
│ └ layout.html
└ static/
└ style.css
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['GET'])
def input():
return render_template('input.html', title='入力ページ')
@app.route('/', methods=['POST'])
def output():
name = request.form['name']
age = request.form['age']
return render_template('output.html', name=name, age=age, title='出力ページ')
if __name__ == '__main__':
app.run(debug=True)
値 | 説明 |
---|---|
request.method |
HTMLのformタグのmethod属性が指定したメソッドタイプを取得 |
request.form['formのname属性値'] |
HTMLのformタグで送信される<input type="hoge"> のクエリパラメータを取得 |
request.files['formのname属性値'] |
HTMLのformタグで送信されるファイルを取得 |
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{{ title }}</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
{% block content %}
<!-- ここに個別部分が挿入される -->
{% endblock %}
</body>
</html>
{% extends "layout.html" %}
{% block content %}
<form action="/" method="POST" enctype="multipart/form-data">
<input type="text" id="name" name="name" placeholder="名前">
<input type="number" id="age" name="age" placeholder="年齢">
<input class="submit-button" value="実行する" type="submit">
</form>
{% endblock %}
formタグのenctype属性の値は、multipart/form-data
にしないと400エラーを引き起こします。
{% extends "layout.html" %}
{% block content %}
<p>名前:{{ name }}</p>
<p>年齢:{{ age }}歳</p>
{% endblock %}
body {
background: #F4E7D3;
}
p {
color: #1F4E5F;
}
さいごに
今回はFlaskのJinja2テンプレートエンジンの記法を紹介しました。
必要に応じて更新するので、こまめに見に来たら良いことがあるかもしれない…。笑
それでは!