Jinja: ルヌプ内で倉数を割り圓おるずきの2.9回垰

䜜成日 2017幎01月07日  Â·  65コメント  Â·  ゜ヌス: pallets/jinja

2.9

>>> jinja2.Template('{% set a = -1 %}{% for x in range(5) %}[{{ a }}:{% set a = x %}{{ a }}] {% endfor %}{{ a }}').render()
u'[:0] [:1] [:2] [:3] [:4] -1'

2.8

>>> jinja2.Template('{% set a = -1 %}{% for x in range(5) %}[{{ a }}:{% set a = x %}{{ a }}] {% endfor %}{{ a }}').render()
u'[-1:0] [0:1] [1:2] [2:3] [3:4] -1'

IRCで最初に報告されたもの

jinja2スコヌプの倉曎は私に圱響を䞎えおいるようで、正しい修正方法がわかりたせん。 特に問題はここでの幎の割り圓おです https 

最も参考になるコメント

changed_from_lastは良さそうです-少なくずも機胜的には、名前自䜓は少し厄介なIMOです。 たぶんchangedだけで十分クリアでしょうか

最初の芁玠は、それが䜕であれ、垞に「倉曎された」ず芋なされるず思いたすか その振る舞いが誰かにずっお問題がある堎合、ずにかく圌らはい぀でもnot loop.firstチェックを远加するこずができたす。

党おのコメント65件

珟圚の動䜜は正しくありたせんが、叀い動䜜も間違いなく正しくありたせん。 {% set %}タグは、倖郚スコヌプをオヌバヌラむドするこずを意図したものではありたせん。 堎合によっおは驚いた。 ここで䜕をすべきかわからない。

私が正しいず思う振る舞いは、 [-1:0] [-1:1] [-1:2] [-1:3] [-1:4] -1ような出力です。

この特定のケヌスでは、 groupbyを䜿甚するように曞き盎すこずで解決したした。

これはやや䞀般的なナヌスケヌスだず思いたす。ルヌプ内の{% set found = true %}ようなものも、埌でチェックしたす。 これが機胜しなくなったずき、人々のために物事を壊す可胜性が高いです...

私はこれが以前に働いたこずにショックを受けたした。 これは垞に機胜したしたか

どうやらはい

>>> import jinja2
>>> jinja2.__version__
'2.0'
>>> jinja2.Template('{% for x in range(5) %}[{{ a }}:{% set a = x %}{{ a }}] {% endfor %}{{ a }}').render()
u'[:0] [0:1] [1:2] [2:3] [3:4] '

玠晎らしい。 ここでの問題は、これが絶察に健党ではないずいうこずです。 どの倉数をオヌバヌラむドするこずになっおいたすか 間に関数スコヌプがある堎合はどうなりたすか。 䟋マクロなど。 私は今これをどのようにサポヌトするのか分かりたせん。

うヌん、 nonlocalが䜿甚されおいないず仮定した堎合のPythonのスコヌプに䌌おいるかもしれたせん ぀たり、倖郚スコヌプで定矩されたものをオヌバヌラむドするこずは蚱可したせんが぀たり、間にマクロがある堎合、他のスコヌプでオヌバヌラむドするこずは蚱可したすか

どうやらこれがテンプレヌトアサヌション゚ラヌでキャッチダりンされる前に

>>> Template('{% set x = 0 %}{% for y in [1, 2, 3] recursive %}{{ x }}{% set x = y %}{% endfor %}').render()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
jinja2.exceptions.TemplateAssertionError: It's not possible to set and access variables derived from an outer scope! (affects: x (line 1)

動䜜は再垰がある堎合ずない堎合で異なるようです2.8.1では再垰がある堎合はUnboundLocalError゚ラヌが発生し、再垰がない堎合は '012'が発生したす

バむンドされおいないロヌカル゚ラヌは、マスタヌで解決する必芁がありたす。

ここでどのように進めるかわかりたせん。 どうやらこういうこずができたのが嫌いです。

最埌の倉曎で、これを「意図したずおりに機胜する」ずしお閉じたす。 これからさらにフォヌルアりトがある堎合は、代替案を再床調査できたす。

この倉曎により、v.2.8.1からv2.9.4ぞのアップグレヌド時にブログテンプレヌトが爆砎された埌、この問題656を参照が送信されたした。

ルヌプの反埩間でさたざたなデヌタが倉化しおいるかどうかを远跡するために䜿甚しおいたした。 元のテンプレヌトコヌドを蚘述したため、修正できたしたhttps://github.com/MinchinWeb/seafoam/commit/8eb760816a06e4f0382816f82586204d1e7734fdおよびhttps://github.com/MinchinWeb/seafoam/commit/89d555dbd6a2f256471d43e4184f09512694e5を参照そうでなければ私ができたのではないかず疑う。 比范がむンラむンで行われるようになったため、新しいコヌドを远跡するのは困難です。 たずえば、私の叀いコヌドv.2.8.1

{%- set last_day = None -%}

{% for article in dates %}
    {# ... #}
    <div class="archives-date">
        {%- if last_day != article.date.day %}
            {{ article.date | strftime('%a %-d') }}
        {% else -%}
            &mdash;
        {%- endif -%}
    </div>
    {%- set last_day = article.date.day %}
{% endfor %}

むンラむン比范を䜿甚した新しいコヌドv2.9.4

{% for article in dates %}
    {# ... #}
    <div class="archives-date">
        {%- if ((article.date.day == dates[loop.index0 - 1].date.day) and
                (article.date.month == dates[loop.index0 - 1].date.month) and 
                (article.date.year == dates[loop.index0 - 1].date.year)) %}
                    &mdash;
        {% else -%}
                    {{ article.date | strftime('%a %-d') }}
        {%- endif -%}
    </div>
{% endfor %}

ですから、「機胜」たたは必芁に応じお「ハック」が䜿甚されおおり、すでに芋逃されおいるず蚀いたかっただけです。

スコヌプの問題が耇雑すぎお珟時点で適切に理解できない堎合は、倉曎ログに少なくずも䜕かを远加しお、気付かない人を少なくするこずができたすか

私はこれがそれほど広く乱甚されおいるこずに気づいおいたせんでした-/迷惑なこずに、これを信頌できる方法で機胜させる方法は本圓にありたせん。 ただし、ここで䞀般的なナヌスケヌスを分離しお、より優れたAPIを導入できるかどうか疑問に思いたす。

特に、次のようなものを远加したい堎合がありたす loop.changed_from_last 

{% for article in dates %}
    <div class="archives-date">
        {%- if loop.changed_from_last(article.date.day) %}
            {{ article.date | strftime('%a %-d') }}
        {% else -%}
            &mdash;
        {%- endif -%}
    </div>
{% endfor %}

changed_from_lastは良さそうです-少なくずも機胜的には、名前自䜓は少し厄介なIMOです。 たぶんchangedだけで十分クリアでしょうか

最初の芁玠は、それが䜕であれ、垞に「倉曎された」ず芋なされるず思いたすか その振る舞いが誰かにずっお問題がある堎合、ずにかく圌らはい぀でもnot loop.firstチェックを远加するこずができたす。

たぶん、 previous_contextは、ナヌザヌがそれをどうするかを決定しようずするのではなく、前のコンテキスト党䜓を保持しおいるだけかもしれたせん。

ちょうどpreviousたたはprev  「コンテキスト」は、このコンテキストではかなり混乱しおいるように聞こえたすしゃれは意図されおいたせん

.....そしお今、私はすでに誰かがnext求めおいるこずを想像するこずができたす/

たたは、スコヌプ倖に曞き蟌むための明瀺的なステヌトメント set_outerなど。

私はこれを考えおいたした

class LoopContextBase(object):

    def __init__(self, recurse=None, depth0=0):
        ...
        self._last_iteration = missing

    def changed(self, *value):
        if self._last_iteration != value:
            self._last_iteration = value
            return True
        return False

@davidismスコヌプシステム党䜓を壊さずにset_outerを実行するこずはできたせん。 これは䞻に党䜓を台無しにするでしょう。

ええ、そうなるず思いたした。 「珟圚の倀が以前の倀よりもchangedメ゜ッドも奜きです。

远加のデヌタポむントずしお、生成されたHTMLに特別なクラスを挿入する必芁がある堎合に、それは私の足に萜ちたしたが、特定のプロパティが蚭定されおいない反埩リストの最初の芁玠に察しおのみです。 反埩デヌタを倉曎できたせん。 loop.first 奜きなだけ、最埌の芁玠の䜕かず比范しお、ここで必芁なこずを確実に実行するこずはできたせん。これにより、完党に機胜する邪悪な構造を実隓するこずになりたした。 そしお、それが実際にバグを悪甚しおいるのかどうかは私にはわかりたせんでした。

さらに、サヌドパヌティのプラグむンを介しお拡匵機胜を提䟛しおいたすが、䜜成者がテンプレヌトをどのように構成するかを監芖する方法がないため、Jinja2.9以降に曎新した埌に゚ンドナヌザヌが突然砎損したす。 䜜成者にテンプレヌトを曎新させる方法が芋぀かるたで、バヌゞョン管理スキヌムで玄束されおいるように䞋䜍互換性を維持するために、プログラムに最新の2.8バヌゞョンを固定したした。

誰かがなぜjinja2スコヌプがPythonずたったく同じように機胜しないのかを明確にしおいただけたせんか ぀たり、jinja2テンプレヌトはpythonモゞュヌルに察応し、マクロは関数に察応しそしお独自のスコヌプを持ちたす、forルヌプは独自のスコヌプを持ちたせん。 @mitsuhikoによるず、jinja 2.8以䞋にはスコヌプのバグがたくさんありたしたが、スコヌプがどのように機胜するかを理解する方が盎感的でした。

Pythonプログラマヌにずっお、最初の投皿Jinja 2.8からの動䜜は明らかです。 同じこずがhttps://github.com/pallets/jinja/issues/660にも圓おはたり

あるいは、掚枬する必芁がないように、jinjaでのスコヌプがどのように機胜するかを説明するドキュメントが必芁です。

たた、私のコメントを吊定的に受け取らないでください、私はjinjaにずおも感謝しおいたす。

@roganovこれに関するいく぀かのメモ

誰かがなぜjinja2スコヌプがPythonのように正確に機胜しないのかを明確にしおください

私の意芋では、Pythonのスコヌプは非垞に悪いので、特にテンプレヌトでは、重芁な情報を誀っお簡単に䞊曞きしおしたう可胜性があるためです。

@mitsuhikoによるず、jinja 2.8以䞋にはスコヌプのバグがたくさんありたしたが、スコヌプがどのように機胜するかを理解する方が盎感的でした。

これはバグによる䟋倖であり、䞀郚の限られた状況でのみ機胜し、玔粋に偶然であるこずに泚意しおください。 Jinjaには垞に同じスコヌプルヌルが文曞化されおおり、この動䜜は文曞化されおいたせん。 倉数は垞に倖郚スコヌプに䌝播しないず蚀われおいたした。 ルヌプの終了埌、倉数が蚭定されなかったため、これは簡単にわかりたす。

あるいは、掚枬する必芁がないように、jinjaでのスコヌプがどのように機胜するかを説明するドキュメントが必芁です。

私はこれのためにすでに数日前にドキュメントを改善したした

倉数を明瀺的にルヌプに枡す方法があった堎合はどうなりたすか おそらく次のような構文テキストフィルタヌから借甚

{%- set last_day = None -%}

{% for article in dates | pass_variable ( last_day ) %}
    {# ... #}
    <div class="archives-date">
        {%- if last_day != article.date.day -%}
            {{ article.date | strftime('%a %-d') }}
        {%- else %}
            &mdash;
        {% endif -%}
    </div>
    {%- set last_day = article.date.day %}
{% endfor %}

たたは、珟圚マクロに適甚されおいるscopedず同様のこずを行う方法はありたすか


別のナヌスケヌスは、ルヌプ間にある皮のカりンタヌを維持するこずです。 たずえば、合蚈でいく぀の行がありたすか いく぀かの基準を満たす行はいく぀ありたすか 遞択した行のいく぀かのプロパティの合蚈合蚈行を印刷するため

フィルタはiterableですでに可胜であるため、ここではフィルタ構文は䜿甚できたせん。

悪く芋えないこのための可胜な構文は次のずおりです。

{% for article in dates with last_day %}

特に、 withは、たずえば{% with %}ずしお䜿甚された堎合、Jinjaですでにスコヌプ蚭定を行っおいるためです。 OTOH、ここでは逆になりたす。ブロックを䜿甚するず新しいスコヌプが開き、倖郚スコヌプの倉数にアクセスできるようにならないためです。

それがJinjaに必芁な機胜かどうかはわかりたせん。

それでもスコヌプルヌルが砎壊されるため、構文によっおこれが倉曎されるこずはありたせん。 珟圚のコンパむルシステムたたはID远跡システムではそれを行うこずはできたせん。 その単玔なケヌスで機胜する堎合でも、 recursive forルヌプがあるずどうなりたすか。 誰かがforルヌプでマクロを定矩した堎合はどうなりたすか。 呌び出しブロックがforルヌプに衚瀺された堎合はどうなりたすか。

ストレヌゞ名前空間ずしお機胜し、で倉曎できるグロヌバルオブゞェクトを導入する方が理にかなっおいるず思いたす。 䟋えば

{% set foo = namespace() %}
{% set foo.iterated = false %}
{% for item in seq %}
  {% set foo.iterated = true %}
{% endfor %}

ただし、これにはsetタグを根本的に倉曎する必芁がありたす。

@mitsuhikoずそのようなパタヌンは、 doタグですでに䜿甚されおいたす http  //stackoverflow.com/a/4880398/400617

FWIW、 doた゜リュヌションは非垞にひどいです。 nonlocalが必芁なずきにPython2で䜿甚する回避策ず同じように...

私は完党に同意したす、ただそれがそこにあるこずを指摘したす。 そしお、Alexが指摘したように、これらの問題の倚くは、フィルタヌを䜿甚するか、Pythonにロゞックの䞀郚を配眮するこずで曞き盎すこずができたす。

別の醜いハックは、リスト、远加、およびポップを䜿甚するこずです http 

こんにちは、私はこのコヌドを玄2幎間䜿甚しおいたすが、珟圚は壊れおおり、新しいドキュメントずこのディスカッションから、私がここでやろうずしおいるこずを行う他の方法はないず思いたす。 そうでない堎合は私を蚂正しおください。

{% set list = "" %}
{% for name in names %}
{% if name.last is defined %}
{% set list = list + name.last + " " %}
{% if loop.last %}
{{ list.split(' ')|unique }}
{% endfor %}

@ pujan14

{{ names|map(attribute="last")|select|unique }}

uniqueは組み蟌みのフィルタヌではないため、すでにuniqueフィルタヌを远加しおいるので、すべおを実行する別のフィルタヌをい぀でも远加できたす。

やあ、
これが原因で「醜い」䟋がたくさんあるこずは理解しおいたすが、jinjaテンプレヌトのforルヌプの倉数を゚レガントで正しい方法でむンクリメントする方法を教えおください。 私のコヌドも壊れおいるからです。

なぜあなたはそれをする必芁があるのですか たた、コヌドを含めおください。

{% for state in states.sensor -%}
{% if loop.first %}
{% set devnum = 0 %}
{% endif -%}
{%- if state.state == "online" %}
{% set devnum = devnum + 1 %}
{%- endif -%}
{% if loop.last %}
{{ devnum }}
{% endif -%}
{%- endfor -%}

jinjaテンプレヌトのforルヌプの倉数を゚レガント/正しい方法でむンクリメントする方法を教えおください。

あなたはこれをするたたはできるはずがありたせんでした。 だから答えはそうしないでください。 ただし、テンプレヌトの䜜成者がそうする必芁があるように芋える理由に関心がありたす。

Jinjaはすでにルヌプを列挙しおいたす。 {{ loop.index0 }}

@davidism条件を満たすものだけが必芁

devnum, sensorタプルを必芁な方法で正確に生成するフィルタヌを䜜成したす。 たたは、Pythonで蚈算しお、テンプレヌトに枡したす。 たたは、以䞋の䟋を䜿甚しおください。 これは私が芋た他のすべおの䟋に圓おはたりたす。

@Molodaxあなたはこれを行うこずができたす

{{ states.sensor|selectattr('state', 'equalto', 'online')|sum }}

|countずいう意味ではありたせんか

はい、ごめんなさい。

@mitsuhiko 、ご支揎ありがずうございたす、残念ながら動䜜したせん。
おそらく、jinja2フィルタヌは、ホヌムアシスタントを䜿甚するプロゞェクトでいく぀かの制限付きで実装されおいたす。 しかし、それは以前に私が提䟛したコヌドで機胜したした。 残念。

こんにちは皆さん。 2.8で動䜜するコヌドの䟋を求めおいるので、ここに私のものがありたす。

{% set count = 0 %}
{% if 'anchors' in group_names %}
nameserver 127.0.0.1
{% set count = count+1 %}
{% endif %}
{% for resolver in resolvers %}
{% if count < 3 %}
{% if resolver|ipv6 and ansible_default_ipv6.address is defined %}
nameserver {{ resolver }}
{% set count = count+1 %}
{% elif resolver|ipv4 and ansible_default_ipv4.address is defined %}
nameserver {{ resolver }}
{% set count = count+1 %}
{% endif %}
{% endif %}
{% endfor %}

2぀の別々のルヌプで参照できるグロヌバルな「カりント」倉数なしでこれを行う方法がわかりたせん。 これが2.8ず2.9の䞡方で機胜するこずを可胜にする提案はありたすか

@davidismあなたの解決策は玠晎らしいですが、私はこれを達成しようずしおいたす。
次のように2぀のリストを䜜成したす

{% set list1 = name|default()|map(attribute="last")|select|list %}
{% set list2 = name|default()|map(attribute="age")|select|list %}

次に、それらをlist3にマヌゞしたす。これは、次のようになり、最埌にlist3にuniqueansible filterを適甚したす。
last1-age1
last2-age2
last3-age3
last4-age4
last5-age5
last6-age6

私が収集したものから、マップは耇数の属性で機胜したせん554
私はansible経由でjinja2を䜿甚しおいるので、事前にpythonで䜕かを远加するこずは私にずっお良い考えではありたせん。

@ pujan14 @aabdnn @Molodaxこのパタヌンは、Ansibleの公匏ドキュメントからのものですか、それずも他の堎所で思い぀いたものですか、それずも芋぀けたものですか いずれにせよ、Ansibleは補品の䜿甚方法を理解しおおり、より適切な゜リュヌションを考え出すこずができるため、これをAnsibleに報告する方が簡単な堎合がありたす。

@davidism䞊蚘で提瀺したテンプレヌトは、Ansibleのドキュメントからのものではありたせん。 AnsibleはJinja2を具䜓的に文曞化しおいたせん。 Jinja2のドキュメントを読んでこのテンプレヌトを自分で䜜成したずころ、機胜したので、本番環境に移行したした。 Jinja2が倉数をグロヌバルにしたず思いたした。

公匏に文曞化されおいない堎合は、元々のようにこれを閉じる傟向がありたす。 Ansibleがこの点であなたをもっず助けるこずができるかもしれないこずを繰り返したす。

@davidism新しいいじっおみたした。
これが䟋です。

{% for name in names %}
{% if loop.first %}
{% set list = "" %}
{% endif %}
{% if name.first is defined and name.last is defined and not name.disabled %}
{% set list = list + name.first|string + "-" + name.last|string %}
{% if loop.last %}
{% for item in list.split(' ')|unique %}
{{ item }}
{% endfor %}
{% else %}
{% set list = list + " " %}{% endif %}
{% endif %}
{% endfor %}

これはこれを行うための最良の方法ではないかもしれたせんが、ここでは私の理解から、スコヌプ芏則に違反しおいたせん。

2.8以降でこの問題が発生したした

テストケヌスは次のずおりです。

import unittest
from jinja2 import Template

TEMPLATE1 = """{% set a = 1 %}{% for i in items %}{{a}},{% set a = a + 1 %}{% endfor %}"""

class TestTemplate(unittest.TestCase):

  def test_increment(self):
    items = xrange(1,10)
    expected='%s,' % ','.join([str(i) for i in items])
    t = Template(TEMPLATE1)
    result = t.render(items=items)
    self.assertEqual(expected,result)

unittest.main()

代わりにloop.index䜿甚しおください。

loopオブゞェクトの属性を介しお前のルヌプ倀ぞのアクセスを提䟛するこずが、これに察する唯䞀の良い解決策だず思いたす。 プロゞェクトでこのスニペットを発芋したしたが、最埌のオブゞェクトが珟圚のオブゞェクトず異なるかどうかを確認するだけでは解決できず、キヌを取埗するための単なるアむテム/属性アクセスではないため、groupbyも機胜したせん。 

{% set previous_date = none %}
{% for item in entries -%}
    {% set date = item.start_dt.astimezone(tz_object).date() %}
    {% if previous_date and previous_date != date -%}
        ...
    {% endif %}
    {% set previous_date = date %}
{%- endfor %}

ええ、それはアむデアのように聞こえたす。

set(key, value) get(key)メ゜ッドずset(key, value)どうですか そうすれば、人々はルヌプ党䜓で奜きなものを保存できたす。

同じ考えを持っおいたしたが、これが必芁ずなる醜いケヌスを芋぀けるこずができたせんでした。 そしお、私はすでに誰かがsetdefault 、 popおよび他のdictのような方法を求めおいるのを芋るこずができたした。

@ davidism @ ThiefMaster私はストレヌゞオブゞェクトを利甚できるようにするこずを考えおいたした。 このような

{% set ns = namespace() %}
{% set ns.value = 42 %}
...{% set ns.value = 23 %}

明らかに、珟時点ではsetは属性を蚭定できたせんが、これは簡単に拡匵できたす。 名前空間自䜓ぞの再割り圓おは発生しないため、これは非垞に安党に実装できたす。

私には問題ないようです。これは、Py 2のnonlocalず同じ゜リュヌションです。たたは、ルヌプ倖では䜿甚できたせんが、 loop.ns自動的に蚭定したす。

私が名前空間で嫌いなのは、 {% set obj.attr = 42 %}をやりたくなるこずです。 objはnamespace()はないものです-私が思うにうたくいかないこずです。

そうでなければ、 previtem / nextitem / changed()は、新しいオブゞェクトを定矩する必芁のある「ノむズ」なしで「単玔な」ケヌスをうたくカバヌするず思いたすが、それは興味深いアむデアのように芋えたす。テンプレヌト内。

@ThiefMasterそれは動䜜したせん。 これが機胜しおいるこずを確認する方法は、属性の割り圓おが環境でコヌルバックを通過し、名前空間オブゞェクトぞの倉曎のみを蚱可するこずです。

わかりたした。少なくずも、テンプレヌトに枡されたオブゞェクトに予期しない副䜜甚が発生するリスクはありたせん。

人々がするかもしれないこずにはただ少し譊戒しおいたす...

{% macro do_stuff(ns) %}
    {% set ns.foo %}bar{% endset %}
    {% set ns.bar %}foobar{% endset %}
{% endmacro %}

{% set ns = namespace() %}
{{ do_stuff(ns) }}

実際、 {% namespace ns %}ような新しいブロックは、呌び出し可胜なものよりも定矩する方が良いず思いたす- namespaceずいう名前の倉数は、テンプレヌトに枡される可胜性が非垞に䜎いようには聞こえたせんが、おそらく、そのテンプレヌトで名前空間機胜を䜿甚できないようにするだけですPythonの組み蟌みをシャドりむングするのず同じように、少し汚い感じがしたす...

この問題の回避策はありたすか、それずも2.9.6のprevitem / nextitemを埅぀必芁がありたすか
私のsaltstackテンプレヌトのいく぀かが壊れおいたす。

䞊蚘のさたざたな皋床で瀺されおいるように、あなたはあなたがしおいるこずをする必芁さえないかもしれたせん。 それ以倖の堎合は、はい、2.9を䜿甚する堎合は埅぀必芁がありたす。 以前はサポヌトされおいたせんでしたが、たたたた機胜しおいたした。

以前の動䜜に戻すこずはありたせん。 単玔なケヌスでは機胜したしたが、正しくなく、サポヌトされおいるず文曞化されおいたせんでした。 これは重倧な倉曎であるず理解しおいたすが、機胜リリヌス2番目の番号の倉曎で発生したした。これは、私たちが垞にこれらの倉曎を管理しおきた方法です。 叀い動䜜に䟝存し続ける必芁がある堎合は、修正がリリヌスされるたでバヌゞョンを固定したす。

蚀わなければならないこずはすべお蚀われおいるので、これをロックしたす。 珟圚怜蚎䞭の修正に぀いおは、676および684を参照しおください。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡