Pythonのテンプレートエンジン Jinja2

PythonのJinja2についてのメモ


インストール

pipまたはパッケージシステムで。自分はMsys2環境なのでpacmanでインストール

% pacman -S mingw-w64-x86_64-python-jinja

pipの場合は

% pip install jinja2        # Windows
% sudo pip3 install jinja2  # Linux

テンプレートの読み込み方法

直接文字列を指定

jinja2.Templateクラスのコンストラクタに文字列を渡すことでテンプレートの作成が可能です。ちなみにJinja2はUTF-8しかサポートしていないようです

from jinja2 import Template

# 文字列からテンプレートを作成
template = Template('My name is {{name}}')
txt = template.render(name='Nanashi')

print(txt)
My name is Nanashi

ファイルから読み込み

jinja2.Environmentクラスを作成し、そこからファイルを読み込みます

from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader(searchpath=['python']))
template = env.get_template('test.j2')
txt = template.render(name='Gonbei')
print(txt)
My name is Gonbei

FileSystemLoadersearchpath引数にはファイルを検索するパスを指定可能です


テンプレート記述方法

デリミタ

テンプレートテキストの中でJinja2のテンプレートエンジンで処理される特別な意味を持つ箇所 (デリミタ)は以下の4つです

  • {% ... %} for Statements (if文やforループなど)
  • {{ ... }} for Expressions (変数の値で置換)
  • {# ... #} for Comments (コメント。出力には含まれない)
  • #  ... ## for Line Statements (Statementsの簡易記法。有効化が必要)

if文

{% if ... %}により変数による出力切り替えが可能です

My name is {{name}}
{% if gender == 'male' %}
I am a man
{% else %}
I am a woman
{% endif %}
txt = template.render(name='Gonbei', gender='male')
print(txt)
My name is Gonbei

I am a man

for文

{% for ... %} ... {% endfor}により、ブロック内のテキストを繰り返し生成することが可能です

{% for person in members %}
My name is {{person.name}}.
{%- if person.gender == 'male' %}
I am a man
{%- else %}
I am a woman
{%- endif %}
{% endfor %}
class Person:
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

env = Environment(loader=FileSystemLoader(searchpath=['python']))
template = env.get_template('test.j2')
txt = template.render(members=[Person('Mike', 'male'),
                               Person('Nancy', 'female')])
print(txt)
My name is Mike.
I am a man

My name is Nancy.
I am a woman

{%--を付加しているため、前後の改行が削除されて出力されています

マクロ

マクロを定義して、繰り返し出てくる記述を簡略化することができます

{% macro print_person(name, gender) -%}
- Name: {{name}}, Gender: {{gender}}
{%- endmacro %}
{% for person in members -%}
{{print_person(person.name, person.gender)}}
{% endfor %}
class Person:
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

env = Environment(loader=FileSystemLoader(searchpath=['python']))
template = env.get_template('test.j2')
txt = template.render(members=[Person('Mike', 'male'),
                               Person('Nancy', 'female')])
print(txt)
- Name: Mike, Gender: male
- Name: Nancy, Gender: female

Call

callを使用することで、マクロにブロックを挿入することができます。マクロのブロックを挿入したい箇所でcaller()を呼び出します

{% macro print_person_desc(name, gender) -%}
- Name: {{name}}, Gender: {{gender}}
  {{caller()}}
{%- endmacro %}

{% for person in members %}
{% call print_person_desc(person.name, person.gender) -%}
**{{person.description}}**
{%- endcall %}
{% endfor %}
class Person:
    def __init__(self, name, gender, description=None):
        self.name = name
        self.gender = gender
        self.description = description

env = Environment(loader=FileSystemLoader(searchpath=['python']))
template = env.get_template('test.j2')
txt = template.render(members=[Person('Mike', 'male', 'I like orange'),
                               Person('Nancy', 'female', 'I like apple')])
print(txt)
- Name: Mike, Gender: male
  **I like orange**

- Name: Nancy, Gender: female
  **I like apple**

おすすめ