【随時更新】Flaskのjinja2テンプレートエンジンのチートシート

こんにちは、データサイエンティストのたぬ(@tanuhack)です。

Pythonの軽量フレームワーク『Flask』のテンプレートエンジンと言えばjinja2ですね!

シンプルで簡単にコードが書けるのがjinja2の良いところなのですが、公式リファレンスが英語なのと、見返すのが面倒なので、自分へのメモがてらjinja2の記法チートシートなるものを作成してみました。

render_template関数

HTMLを読み込む

Flaskパッケージのrender_template関数を使って、簡単にHTMLファイルを読み込むことができます。

その際、読み込みたいHTMLファイルは、templatesフォルダの中に必ず格納しなければなりません。以下のディレクトリを参考にしてください。

『jinja2_test』という作業フォルダを作成して、PythonとHTMLファイルを格納します。

jinja2_test/
├ app.py
templates/
  └ index.html
  • 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)
  • index.html
  • <!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>
    確認用URL→ http://127.0.0.1:5000/

    CSSを読み込む

    FlaskでCSSやJavaScript、IMAGEファイルを読み込みたい場合は、以下のディレクトリのようにstaticフォルダを作成し、その中に該当ファイル(※今回はCSSファイル)を格納します。

    jinja2_test/
    ├ app.py
    ├ templates/
    │ └ index.html
    static/
      └ style.css

    CSSファイルを読み込む際に気をつけるポイントは、app.pyrender_template関数でHTMLファイルをレンダリングしているので、index.htmlでCSSファイルを読み込むの方法は、app.pyから見たディレクトリを指定します。

  • 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)
  • index.html
  • <!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>
  • style.css
  • body {
      background: #F4E7D3;
    }
    h1 {
      color: #B01335;
    }
    p {
      color: #1F4E5F;
    }
    確認用URL→ http://127.0.0.1:5000/

    テンプレート継承

    各HTMLページで共通する部分は、1つのHTMLファイル(※今回はlayout.html)に記述して、それを継承することができます。

    具体的には、個別ページで{% extends "layout.html" %}と先頭行に記述し、共通ページを継承します。

    jinja2_test/
    ├ app.py
    ├ templates/
    │ ├ index.html
    │ └ layout.html
    └ static/
      └ style.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)
  • layout.html|共通部分
  • <!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>
  • index.html|個別部分
  • {% extends "layout.html" %}
    {% block content %}
    <h1>テンプレート継承</h1>
    <p>index.htmlは、layout.htmlを継承しています。</p>
    {% endblock %}
  • style.css
  • body {
      background: #F4E7D3;
    }
    h1 {
      color: #B01335;
    }
    p {
      color: #1F4E5F;
    }
    確認用URL→ http://127.0.0.1:5000/

    変数取得

    この章では、サーバーサイド(Python)からクライアントサイド(HTML)に値を渡す方法を紹介します。

    具体的には、render_template関数に引数を設定することで、値(文字列、リスト、辞書など)を渡すことができます。

    文字列

    クライアントサイドで文字列を受け取る場合、{{ hoge }}のように、サーバーサイドで設定した引数と同じ値を{{ }}の中に記述します。

    jinja2_test/
    ├ app.py
    └ templates/
      └ index.html
  • app.py
  • 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変数にそれぞれ文字列を格納し、クライアントサイドに文字列を渡しています。

  • index.html
  • <!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>
    確認用URL→ http://127.0.0.1:5000/

    リスト

    jinja2_test/
    ├ app.py
    └ templates/
      └ index.html
  • app.py
  • 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)
  • index.html
  • <!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>
    確認用URL→ http://127.0.0.1:5000/

    辞書型配列

    jinja2_test/
    ├ app.py
    └ templates/
      └ index.html
  • app.py
  • 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)
  • index.html
  • <!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>
    確認用URL→ http://127.0.0.1:5000/

    制御構文

    if文

    jinja2_test/
    ├ app.py
    └ templates/
      └ index.html
  • app.py
  • 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)
  • index.html
  • <!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>
    確認用URL→ http://127.0.0.1:5000/

    for文

    jinja2_test/
    ├ app.py
    └ templates/
      └ index.html
  • app.py
  • 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)
  • index.html
  • <!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>
    確認用URL→ http://127.0.0.1:5000/

    requestモジュールと組み合わせる

    HTMLのFormタグでユーザーから受け取った値をPythonでごにゃごにゃした後、再度クライアントサイドに返す方法を紹介します。

    jinja2_test/
    ├ app.py
    ├ templates/
    │ ├ input.html
    │ ├ output.html
    │ └ layout.html
    └ static/
      └ style.css
  • app.py
  • 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)
    requeestモジュールの使い方
    説明
    request.method HTMLのformタグのmethod属性が指定したメソッドタイプを取得
    request.form['formのname属性値'] HTMLのformタグで送信される<input type="hoge">のクエリパラメータを取得
    request.files['formのname属性値'] HTMLのformタグで送信されるファイルを取得
  • layout.html|共通部分
  • <!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>
  • input.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エラーを引き起こします。

  • output.html|個別部分(出力)
  • {% extends "layout.html" %}
    {% block content %}
    <p>名前:{{ name }}</p>
    <p>年齢:{{ age }}歳</p>
    {% endblock %}
  • style.css
  • body {
      background: #F4E7D3;
    }
    p {
      color: #1F4E5F;
    }
    確認用URL→ http://127.0.0.1:5000/

    さいごに

    今回はFlaskのJinja2テンプレートエンジンの記法を紹介しました。

    必要に応じて更新するので、こまめに見に来たら良いことがあるかもしれない…。笑

    それでは!