次のJinjaテンプレートがあります。
{% set mybool = False %}
{% for thing in things %}
<div class='indent1'>
<ul>
{% if current_user %}
{% if current_user.username == thing['created_by']['username'] %}
{% set mybool = True %}
<li>mybool: {{ mybool }}</li> <!-- prints True -->
<li><a href='#'>Edit</a></li>
{% endif %}
{% endif %}
<li>Flag</li>
</ul>
</div>
<hr />
{% endfor %}
{% if not mybool %}
<!-- always prints this -->
<p>mybool is false!</p>
{% else %}
<p>mybool is true!</p>
{% endif %}
for
ループで条件が満たされた場合、mybool
をtrueに変更して、mybool is true!
以下。ただし、内部mybool
のスコープはif
ステートメントに制限されているように見えるため、desiredmybool
は設定しないでください。
最後のmybool
ステートメントで使用できるように「グローバル」if
を設定するにはどうすればよいですか?
[〜#〜] edit [〜#〜]
一部の提案 (キャッシュされたページビューのみが正しく表示される)が見つかりましたが、機能していないようです。おそらく、Jinja2で非推奨になりました...
[〜#〜] edit [〜#〜]
以下にソリューションを提供します。上記の提案がなぜうまくいかないのか、私はまだ興味があります。誰もが彼らが廃止されたことを確かに知っていますか?
この制限を回避する1つの方法は、 "do" expression-statement extension を有効にし、ブール値の代わりに配列を使用することです:
_{% set exists = [] %}
{% for i in range(5) %}
{% if True %}
{% do exists.append(1) %}
{% endif %}
{% endfor %}
{% if exists %}
<!-- exists is true -->
{% endif %}
_
Jinjaの「do」式ステートメント拡張機能を有効にするには:e = jinja2.Environment(extensions=["jinja2.ext.do",])
関連する質問への回答:テンプレートに特定のifブロックを入力した回数のグローバルカウンターが必要でしたが、最終的には次のようになりました。
テンプレートの上部:
{% set counter = ['1'] %}
Ifブロックでカウントしたい:
{% if counter.append('1') %}{% endif %}
カウントを表示する場合:
{{ counter|length }}
文字列'1'
は任意の文字列または数字に置き換えることができると思います。それはまだハックですが、それほど大きなものではありません。
このハック(拡張機能なし)を使用して問題を解決できます。
import jinja2
env = jinja2.Environment()
print env.from_string("""
{% set mybool = [False] %}
{% for thing in things %}
<div class='indent1'>
<ul>
{% if current_user %}
{% if current_user.username == thing['created_by']['username'] %}
{% set _ = mybool.append(not mybool.pop()) %}
<li>mybool: {{ mybool[0] }}</li> <!-- prints True -->
<li><a href='#'>Edit</a></li>
{% endif %}
{% endif %}
<li>Flag</li>
</ul>
</div>
<hr />
{% endfor %}
{% if not mybool[0] %}
<!-- always prints this -->
<p>mybool is false!</p>
{% else %}
<p>mybool is true!</p>
{% endif %}
""").render(current_user={'username':'me'},things=[{'created_by':{'username':'me'}},{'created_by':{'username':'you'}}])
2018年に更新
Jinja 2.1 (2017年11月8日)現在、この特定の問題に対処するnamespace()
オブジェクトがあります。詳細と例については、公式の Assignmentsdocumentation を参照してください。 class
documentation は、いくつかの値を名前空間に割り当てる方法を示しています。
contextfunction()
または類似の何かを書くとき、あなたはコンテキストがあなたがそれを修正するのを止めようとすることに気づくかもしれません。
内部コンテキストAPIを使用してコンテキストを変更できた場合、コンテキストの変更がテンプレートに表示されないように思われるかもしれません。これは、Jinja
がパフォーマンス上の理由からテンプレート変数のプライマリデータソースとしてのみコンテキストを使用するためです。
コンテキストを変更する場合は、setを使用して変数に割り当てる代わりに変数を返す関数を作成します。
{% set comments = get_latest_comments() %}
リスト(objects_from_db)からオブジェクト(オブジェクト)のエントリの最大数を見つける必要がありました。
これは、jinja2および変数スコープで知られている理由で機能しませんでした。
{% set maxlength = 0 %}
{% for object in objects_from_db %}
{% set ilen = object.entries | length %}
{% if maxlength < ilen %}
{% set maxlength = ilen %}
{% endif %}
{% endfor %}
動作するものは次のとおりです。
{% set mlength = [0]%}
{% for object in objects_from_db %}
{% set ilen = object.entries | length %}
{% if mlength[0] < ilen %}
{% set _ = mlength.pop() %}
{% set _ = mlength.append(ilen)%}
{% endif %}
{% endfor %}
{% set maxlength = mlength[0] %}
これが他の誰かが同じことを理解しようとしているのを助けることを願っています。
このすばらしい 記事 が見つかりました。別のスコープでjinja変数の値を変更することはできませんが、グローバル辞書の値を変更することはできます。
# works because dictionary pointer cannot change, but entries can
{% set users = ['alice','bob','eve'] %}
{% set foundUser = { 'flag': False } %}
initial-check-on-global-foundUser:
cmd.run:
name: echo initial foundUser = {{foundUser.flag}}
{% for user in users %}
{%- if user == "bob" %}
{%- if foundUser.update({'flag':True}) %}{%- endif %}
{%- endif %}
echo-for-{{user}}:
cmd.run:
name: echo my name is {{user}}, has bob been found? {{foundUser.flag}}
{% endfor %}
final-check-on-global-foundUser:
cmd.run:
name: echo final foundUser = {{foundUser.flag}}
また、実際にset
を使用せずに値を設定するために、この構文が非常に役立つこともわかりました。
{%- if foundUser.update({'flag':True}) %}{%- endif %}
実際には、辞書に対するupdate
操作の結果をチェックします(自己注意)。