Jinja2入門

記事タイトルとURLをコピーする

こんにちは。AWS CLIが好きな福島です。

インフラエンジニアのキャリアがメインの私が社内でPythonを使ったアプリ開発の学習をする機会があったため、先日から学んだことをアウトプットしています。

先日、FlaskBootstrap入門に関するブログを書きましたが、 今回はJinja2入門のブログをまとめたいと思います。

参考情報

Jinja2とは

一言で言うと、テンプレートエンジンです。

テンプレートエンジンとは以下のイメージで、テンプレートと入力データを基に新たな成果物を生成するソフトウェアです。

上記ではJinja2を使うメリットを感じられないかもしれませんが、以下などの機能により柔軟な成果物の生成やテンプレート管理の簡素化をすることができます。

  • for,ifなどの利用
  • テンプレートから他のテンプレートの読み込み(include)機能

Jinja2を使ってみる

まずは、Jinja2をインストールします。

pip install Jinja2

次に以下のフォルダ構成でファイルを作成します。

フォルダ構成

sample-jinja
├── app.py
└── templates
    └── index.html

index.html

こんにちは!
{{ name }} さん!

app.py

from jinja2 import Environment, FileSystemLoader, select_autoescape
env = Environment(
    ## 読み込みたいフォルダを指定
    loader= FileSystemLoader("templates"),
    autoescape=select_autoescape()
)

## 読み込みたいファイルを指定
template = env.get_template("index.html")

print(template.render(name="kazuya")

ファイルの準備が完了したら、python app.pyを実行します。 index.htmlのnameに入力データのkazuyaが値が入り表示されていることが分かります。

$ python app.py 
こんにちは!
kazuya さん!
$ 

Jinja2はFlaskに組み込まれている

実は以前ブログを書いたFlaskにJinja2は組み込まれています。

そのため以降は、FlaskからJinja2を呼び出しながら、Jinja2で出来ることを書いていきたいと思います。 Flaskから呼び出す場合は、以下のようにrender_templateモジュールを利用します。

app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/<name>")
def index(name):
    return render_template("index.html",name=name)

index.html

こんにちは!
{{ name }} さん!

ファイルを変更したら、flask run --debugを実行します。 http://127.0.0.1:5000/任意の値にアクセスすると以下の通り表示されます。

$ flask run --debug
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 114-794-361

変数展開

上記のサンプルコードで察している方もいると思いますが、{{ 変数名 }}で変数を展開することができます。

もう少し具体的には、以下の通りです。

  • index.htmlには、{{ 変数名 }}のように書く。
  • app.pyでは、render_template(index.html, 変数名=値)のように書く。

以下のように、複数の変数を渡すこともできます。

index.html

{{ comment }}!
{{ name }} さん!

app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/<name>")
def index(name):
    return render_template("index.html", comment="おはよう", name=name)

また、辞書を渡すこともできます。

  • index.htmlには、{{ 変数名.キー名 }}もしくは{{ 変数名["キー名"] }}のように書く。
  • app.pyでは、render_template(index.html, 変数名=辞書型のデータ))のように書く。

index.html

{{ param.comment }}!
{{ param['name'] }} さん!

app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/<name>")
def index(name):
    param = {"comment": "Hello, World", "name": name}
    return render_template("index.html", param=param)

for文

{% for 変数名 in データ %}{% endfor %}を使うことでプログラミングにおけるfor文と同じような動きをさせることができます。

Pythonの処理と組み合わせると動的にコンテンツを展開できるので、便利ですね。

index.html

{% for user in users %}
  <li>{{ user }}</li>
{% endfor %}

app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/")
def index():
    users = ["Alice", "Bob", "Charlie"]
    return render_template("index.html", users=users)

上記はリスト型を渡していますが、辞書型を渡すこともできます。

index.html

{% for param in params %}
  <li>{{ loop.index }} {{ param.name }}: {{ param.age }}</li>
{% endfor %}

{{ loop.index }}は、Jinja2の特殊な変数となり、ループ数に応じて1,2,3のように数字が入ります。 (辞書型を使う際に必須な値という訳ではないです。)

ちなみに0から数字を開始したい場合は、{{ loop.index0 }}を利用することができます。

他に利用できる値の詳細は以下を確認ください。

app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/")
def index():
    params = [
        {
            "name": "Alice",
            "age": 21,
        },
        {
            "name": "Bob",
            "age": 29,
        },
        {
            "name": "Charlie",
            "age": 34,
        },
    ]
    return render_template("index.html", params=params)

if文

if文も使うことができます。以下はname変数の値がある場合は、nameの値を表示し、 name変数の値がない場合は、Name Not Foundの値を表示します。

わざわざ2つのテンプレートを用意する必要がないため、便利ですね。

index.html

{% if name %}
    <li>{{ name }}</li>
{% else %}
    <li>Name Not Found</li>
{% endif %}

app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/")
def index():
    return render_template("index.html")


@app.route("/<name>")
def index2(name):
    print(name)
    return render_template("index.html", name=name)

テンプレートの読み込み(include)

続いて、テンプレートの読み込みについての説明です。

Webアプリを作る際に、複数のWebページを作る場合があります。

その際に共通となるヘッダーやフッターは、1つのテンプレートに定義し、 別のテンプレートから参照させることができたら便利だと思います。

そのような場合にテンプレートの読み込み(include)を使います。 今回は、index.htmlからheader.htmlfooter.htmlを読み込みます。

sample-jinja
├── app.py
└── templates
    └── footer.html
    └── header.html
    └── index.html

まず、header.htmlfooter.htmlを作ります。

header.html

<h1>ヘッダー!!</h1>

footer.html

<h1>フッター!!</h1>

次にindex.htmlには、{% include '読み込みたいテンプレート名' %}のように書きます。

index.html

{% include 'header.html' %}
こんにちは!! {{ name }} さん!!
{% include 'footer.html' %}

app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/<name>")
def index(name):
    return render_template("index.html", name=name)

以下のようにheader.htmlfooter.htmlindex.htmlから読み込めていることが分かります。

終わりに

今回は、Jinja2入門に関するブログをまとめてみました。

どなたかのお役に立てれば幸いです。

福島 和弥 (記事一覧)

2019/10 入社

AWS CLIが好きです。