【Python】Jinja2 ~ 繰り返し ~

◾️はじめに

Jinja2の繰り返し(ループ)についてメモ。

目次

【1】for文
【2】ループの制御文
 1)break文
 2)continue文
【3】loop
 1)主なメソッド
 2)サンプル
【4】使用上の注意:変数をループする場合の注意点
 1)NG例
 2)OK例

【1】for文

サンプル

{% for name in name_vals: %}
  <p>Hello, {{ name + " from USA" }}!!!</p>
{% endfor %}

【2】ループの制御文

* if文と組み合わせて使える

1)break文

{% for item in items %}
  {% if item == 'TheEnd' %}
    {% break %} {# ! 注目 ! #}
  {% endif %}
  <li>{{ item }}</li>
{% endfor %}

2)continue文

{% for item in items %}
  {% if item == 'TheSkip' %}
    {% continue %} {# ! 注目 ! #}
  {% endif %}
  <li>{{ item }}</li>
{% endfor %}

【3】loop

* ループを制御するために用意されている loop が便利。

https://techblog.recochoku.jp/3422

1)主なメソッド

* 以下の公式ドキュメントに全てのメソッドが載っている

https://jinja.palletsprojects.com/en/3.0.x/templates/#for

Express Explanations
loop.index ループのインデックスを返す
loop.first 最初のループの場合 True, それ以外は False
loop.last 最後のループの場合 True, それ以外は False
loop.length ループの回数を返す

2)サンプル

{# ループの最後は「,」は要らないので、それを制御する #}
CREATE TABLE demo_table
{% for column in columns %}
{{ column  }} TEXT{% "," if not loop.last else "" %} {# ! 注目 ! #}
{% endfor %}

【4】使用上の注意:変数をループする場合の注意点

* 変数が文字列もしくは1要素のタプルの場合、文字列として扱い
 1文字づつループされてしまう
 => タプルじゃなく、リストならOK

1)NG例

* 今回の例は、以下のようにするのだが、「出力結果(NG) 」をみて分かる通り
 1文字づつループされてしまう(「table_names=['table1']」ならOK)

 + 1要素であれば、SELECT文のみ
 + 複数要素であれば、SELECT文+UNION ALLで繋ぐ

demo.py

from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('./', encoding='utf8')) 
template = env.get_template('./templates/sql.j2')
result = template.render(
  #table_names = 'table1' # NG
  #table_names = ['table1'] # OK
  table_names = ('table1') # NG
  #table_names = ['table1', 'table2', 'table3'] # OK
  #table_names = ('table1', 'table2', 'table3') # OK
)
print(result)

./templates/sql.j2

{%- for table in table_names %}
  SELECT COUNT(*) FROM {{ table }}
  {%- if not loop.last %}
    UNION ALL
  {%- endif %}
{%- endfor %}

出力結果(NG)

  SELECT COUNT(*) FROM t
    UNION ALL
  SELECT COUNT(*) FROM a
    UNION ALL
  SELECT COUNT(*) FROM b
    UNION ALL
  SELECT COUNT(*) FROM l
    UNION ALL
  SELECT COUNT(*) FROM e
    UNION ALL
  SELECT COUNT(*) FROM 1

2)OK例

* 変数の型チェックして対応する

./templates/sql.j2

{%- if table_names is iterable and table_names is not string and table_names is not mapping %}
  {%- for table in table_names %}
    SELECT COUNT(*) FROM {{ table }}
    {%- if not loop.last %}
      UNION ALL
    {%- endif %}
  {%- endfor %}
{%- else %}
  SELECT COUNT(*) FROM {{ tabel_names }}
{%- endif %}

出力結果(OK)

SELECT COUNT(*) FROM table1

関連記事

Jinja2 ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2024/10/19/000848
Jinja2 ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2024/10/18/001757
Jinja2 ~ フィルタ ~
https://dk521123.hatenablog.com/entry/2024/10/20/002622
Jinja2 ~ Macro ~
https://dk521123.hatenablog.com/entry/2023/11/28/235951
Jinja2 ~ 変数 ~
https://dk521123.hatenablog.com/entry/2025/04/05/131421
Jinja2 ~ 条件分岐 ~
https://dk521123.hatenablog.com/entry/2025/04/06/001255
Jinja2 ~ do文 ~
https://dk521123.hatenablog.com/entry/2025/04/03/221326
Jinja2 ~ Whitespace Control ~
https://dk521123.hatenablog.com/entry/2024/10/29/151203
dbt ~ 条件分岐 ~
https://dk521123.hatenablog.com/entry/2024/09/11/003301
Flask ~ jinja2 ~
https://dk521123.hatenablog.com/entry/2018/09/22/142348
標準テンプレートエンジン
https://dk521123.hatenablog.com/entry/2020/01/07/212138