Jinja とは
Jinjaは、Pythonで動的なWebページ、HTML、XML、その他のマークアップ言語を生成するために広く使用される、人気のあるテンプレートエンジンです。
Djangoのテンプレートシステムに触発され、プレゼンテーション層とビジネスロジック層を効率的に分離する方法を提供します。テンプレートの継承、マクロ、フィルター、ループ制御などの強力な機能により、Jinjaを使用することで、開発者は簡単に複雑で動的なテンプレートを作成することができます。
Jinja の使い方
PythonでJinjaを設定するには、Jinjaパッケージをインストールしてテンプレートファイルを作成するというプロセスが必要です。以下は、PythonでJinjaを設定する方法の例です。
- pipを使用してJinjaパッケージをインストールします。
$ pip install jinja2
- 次の内容を持つ
template.html
という名前のテンプレートファイルを作成します。
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ heading }}</h1>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
- Pythonのスクリプトで、
jinja2
モジュールをインポートし、テンプレートファイルを読み込みます。
from jinja2 import Template, FileSystemLoader, Environment
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('template.html')
- テンプレートで使用する変数を定義します。
title = 'My Template'
heading = 'Welcome to my template'
items = ['item 1', 'item 2', 'item 3']
- 定義した変数を使用してテンプレートをレンダリングします。
output = template.render(title=title, heading=heading, items=items)
print(output)
これにより、定義した変数がテンプレートに挿入されたレンダリングされたHTMLコードが出力されます。出力をファイルに書き込むこともでき、Webフレームワークに渡してWebページに表示することもできます。
<!DOCTYPE html>
<html>
<head>
<title>My Template</title>
</head>
<body>
<h1>Welcome to my template</h1>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
</body>
</html>
Jinja の構文
Jinjaの利点の1つは、読みやすく理解しやすいテンプレートを作成できる簡単な構文です。
変数
Jinjaのもっとも一般的な機能の1つは、変数を使用してテンプレートに動的データを挿入できることです。変数はダブルカーリーブラケット{{ variable_name }}
を使用して定義されます。例えば、name
という値がJohn
の変数がある場合、次のようにテンプレートに挿入できます。
<p>My name is {{ name }}.</p>
ループ
Jinjaのもう1つの強力な機能は、リストや辞書などのデータ構造をループ処理することができることです。これは、繰り返しマークアップを生成する必要がある場合や、データを反復処理する必要がある場合に便利です。ループの構文は{% for item in list %} ... {% endfor %}
です。例えば、名前のリストがある場合、次のようにループ処理できます。
<ul>
{% for name in names %}
<li>{{ name }}</li>
{% endfor %}
</ul>
ループ固有の変数
Jinjaでは、ループを使用してアイテムのコレクションを反復処理し、各アイテムにアクションを実行することができます。反復処理中、Jinjaはループをより制御するための特定の変数を提供し、反復処理に関する特定の情報にアクセスできるようにします。Jinjaでのループ固有の変数のリストは次のとおりです。
変数 | 説明 |
---|---|
loop.index |
この変数は、現在の反復インデックスを表します。1 から開始します。 |
loop.index0 |
この変数は、現在の反復インデックスを表します。0 から開始します |
loop.revindex |
この変数は、末尾からの反復回数を表します。1 から開始します。 |
loop.revindex0 |
この変数は、末尾からの反復回数を表します。0 から開始します。 |
loop.first |
この変数は、最初の反復処理中に True になり、それ以外の場合には False になります。 |
loop.last |
この変数は、最後の反復処理中に True になり、それ以外の場合には False になります。 |
loop.length |
この変数は、反復の合計回数を表します。 |
以下は、これらの変数をJinjaで使用する例です。
<ul>
{% for item in items %}
<li>{{ loop.index }}. {{ item }}</li>
{% endfor %}
</ul>
この例では、items
のコレクションを反復処理し、各アイテムを順序なしリスト(<ul>
)に表示しています。 loop.index
変数を使用して、各アイテムに反復インデックスを表示しています。
Jinjaでは、dictsort
フィルタを使用して辞書のリストを反復することもできます。次の例は、これを示しています。
<ul>
{% for item in items|dictsort(attribute='name') %}
<li>{{ item.name }} ({{ item.price }})</li>
{% endfor %}
</ul>
この例では、name
とprice
キーを含む辞書のリストを反復処理しています。反復する前に、dictsort
フィルタを使用してリストをname
属性でソートしています。ループ内では、各辞書の値にアクセスするために、item.name
およびitem.price
の構文を使用しています。
条件文
Jinjaは条件文をサポートしており、特定の条件に基づいてマークアップを表示または非表示にすることができます。条件文の構文は{% if condition %} ... {% endif %}
です。例えば、is_logged_in
という変数がユーザーがログインしているかどうかを示す場合、その値に基づいて異なるコンテンツを表示できます。
{% if is_logged_in %}
<p>Welcome back!</p>
{% else %}
<p>Please log in to continue.</p>
{% endif %}
Jinja の高度な機能
基本的な構文機能に加えて、Jinjaにはマクロやテンプレート継承などの高度な機能があり、テンプレートの柔軟性と効率性をさらに向上させることができます。
マクロ
その高度な機能の1つは、再利用可能なコードスニペット(マクロと呼ばれる)を定義できることです。マクロはプログラミング言語の関数に似ており、共通に使用されるコードをカプセル化してテンプレートを簡素化、整理することができます。
Jinjaでマクロを定義するには、{% macro %}
タグを使用します。例を示します。
{% macro greeting(name) %}
Hello, {{ name }}!
{% endmacro %}
このマクロは、greeting
という名前で、1つの引数name
を受け取ります。{{ name }}
構文を使用してname
変数の値を出力する簡単な挨拶メッセージを返します。
テンプレートでgreeting
マクロを使用するには、{% call %}
タグを使って呼び出します。
{% call greeting('Alice') %}
{% endcall %}
これにより、次の出力がレンダリングされます。
Hello, Alice!
変数をマクロに渡すこともできます。
{% set my_name = 'Bob' %}
{% call greeting(my_name) %}
{% endcall %}
これにより、次の出力がレンダリングされます。
Hello, Bob!
Jinjaでマクロを定義することで、テンプレートで同じコードを繰り返すことを避け、よりモジュラーでメンテナンスしやすいテンプレートを作成できます。
テンプレートの継承
テンプレートの継承は、Jinjaの強力な機能の1つで、1つのテンプレートの共通要素を複数のページで再利用することができます。テンプレートの継承を使用すると、ヘッダーやフッター、ナビゲーションメニューなど、サイトの共通要素を含むベーステンプレートを定義し、その上に子テンプレートを作成して独自のコンテンツを追加することができます。
Jinjaでベーステンプレートを定義するには、{% block %}
タグを使用して、子テンプレートによって上書きできるコンテンツのブロックを定義する必要があります。次に、簡単なベーステンプレートの例を示します。
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
<header>
{% block header %}
<nav>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
{% endblock %}
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
{% block footer %}
© 2023 My Site
{% endblock %}
</footer>
</body>
</html>
この例では、{% block %}
タグでtitle
、header
、footer
の3つのコンテンツブロックが定義されています。これらのブロックの内容は、子テンプレートによって上書きすることができます。
ベーステンプレートから継承した子テンプレートを作成するには、{% extends %}
タグを使用してベーステンプレートの名前を指定し、{% block %}
タグを使用してブロックの内容を上書きする必要があります。以下は、title
とcontent
ブロックを上書きした子テンプレートの例です。
{% extends "base.html" %}
{% block title %}My Page Title{% endblock %}
{% block content %}
<h1>Welcome to my page!</h1>
<p>This is some content for my page.</p>
{% endblock %}
この例では、{% extends %}
タグが子テンプレートがbase.html
テンプレートを継承することを指定しています。{% block %}
タグは、ベーステンプレートで定義されたtitle
とcontent
ブロックをオーバーライドします。
子テンプレートをレンダリングすると、Jinja
は自動的にベーステンプレートを起点として、オーバーライドされたブロックのコンテンツを挿入します。結果として生成されるHTMLには、ベーステンプレートで定義されたサイトの共通要素と、子テンプレートの特定のコンテンツが含まれます。
Jinja による SQL
以下にJinjaを使ってSQL文を記述する例を紹介します。
INSERT
以下は、Pythonで任意の数の行と列を持つSQL INSERTステートメントを生成するためにJinjaを使用する方法の例です。
import jinja2
# define your data
data = [
['Alice', 25, 'Female'],
['Bob', 30, 'Male'],
['Charlie', 40, 'Male'],
]
# define the template
template = """
INSERT INTO my_table (name, age, gender)
VALUES
{% for row in data %}
(
{% for col in row %}
{% if col is string %}
'{{ col }}' {% if not loop.last %},{% endif %}
{% else %}
{{ col }} {% if not loop.last %},{% endif %}
{% endif %}
{% endfor %}
) {% if not loop.last %},{% endif %}
{% endfor %}
"""
# compile the template
template = jinja2.Template(template)
# render the SQL statement with the data
sql_statement = template.render(data=data)
print(sql_statement)
この例では、まず、データをリストのリストとして定義します。各内側のリストは、テーブルに挿入するデータの行を表します。
次に、SQL挿入文をJinjaテンプレートとして定義します。データリスト内の各行を反復処理するためにforループを使用し、行内の各列を反復処理するために別のforループを使用します。 loop.last
変数を使用して、列ごとにカンマを追加しますが、データ内の最後の列や最後の行の後にはカンマを追加しません。
また、現在の列の値が文字列かどうかを確認するために条件文を使用します。文字列である場合は、SQL文に挿入する前に引用符で囲みます。
最後に、Jinjaテンプレートをコンパイルし、データを使用してSQL文をレンダリングします。その結果得られたSQL文をデータベースに対して実行できます。
UPDATE
以下は、JinjaとPythonを使用してSQLテーブルを更新する例です。
import jinja2
# Define the data for the update
update_data = {
'column1': 'new_value1',
'column2': 'new_value2',
'column3': 'new_value3'
}
# Define the Jinja template for the update query
update_query_template = """
UPDATE my_table
SET {% for column, value in update_data.items() %}
{{ column }} = {{ value }}{% if not loop.last %},{% endif %}
{% endfor %}
WHERE id = {{ id }};
"""
# Create the Jinja environment and render the query template
env = jinja2.Environment()
update_query = env.from_string(update_query_template).render(update_data=update_data, id=123)
このコードでは、最初に更新に使用するデータを、列名とその新しい値の辞書として定義します。
次に、更新クエリのJinjaテンプレートを定義します。テンプレートの中で、forループを使用してupdate_data
辞書内の列名と値を反復処理し、それぞれの列を対応する新しい値に設定します。loop.last
変数を使用して、ループの最後の反復かどうかを確認し、SQL構文が正しいことを確認するために、最後の反復でない場合はカンマを追加します。
最後に、Jinja環境を作成し、クエリテンプレートをupdate_data
辞書と更新する行のIDでレンダリングし、データベースコネクタを使用して生成されたクエリを実行します。
参考