Frage

Ich habe zwei for-Schleifen, die beide gleichermaßen in Würde. Ich möchte einen Zähler während jeder inneren Iteration erhöht haben.

Zum Beispiel, betrachten Sie diese Vorlage:

from jinja2 import Template

print Template("""
{% set count = 0 -%}
{% for i in 'a', 'b', 'c' -%}
  {% for j in 'x', 'y', 'z' -%}
    i={{i}}, j={{j}}, count={{count}}
    {% set count = count + 1 -%}
  {% endfor -%}
{% endfor -%}
""").render()

sollte nicht dieser Druck count=0 durch count=8? Nein, es funktioniert nicht.

i=a, j=x, count=0
i=a, j=y, count=1
i=a, j=z, count=2
i=b, j=x, count=0
i=b, j=y, count=1
i=b, j=z, count=2
i=c, j=x, count=0
i=c, j=y, count=1
i=c, j=z, count=2

Was soll das?

. Hinweis: Ich kann nicht einfach speichern die äußere loop Variable, um den Zähler zu berechnen, weil in meiner Software, die Anzahl der inneren Iterationen Variable

War es hilfreich?

Lösung

Mit variabler Innengruppengrößen, dies funktionieren wird:

from jinja2 import Template

items = [
    ['foo', 'bar'],
    ['bax', 'quux', 'ketchup', 'mustard'],
    ['bacon', 'eggs'],
    ]

print Template("""
{% set counter = 0 -%}
{% for group in items -%}
  {% for item in group -%}
    item={{ item }}, count={{ counter + loop.index0 }}
  {% endfor -%}
  {% set counter = counter + group|length %}
{% endfor -%}
""").render(items=items)

... welche druckt:

item=foo, count=0
  item=bar, count=1

item=bax, count=2
  item=quux, count=3
  item=ketchup, count=4
  item=mustard, count=5

item=bacon, count=6
  item=eggs, count=7

Ich denke, Variablen außerhalb up mehr erklärt als eine Ebene der Anwendungsbereich nicht auf oder etwas zugeordnet werden können.

Andere Tipps

Es sieht wie ein Fehler, aber wie über einige dieser Berechnung außerhalb der Vorlage zu verschieben?

from jinja2 import Template

outer_items = list(enumerate("a b c".split()))
inner_items = list(enumerate("x y z".split()))

print Template("""
{% for outer, i in outer_items -%}
  {% for inner, j in inner_items -%}
  {% set count = outer * num_outer + inner -%}
    i={{i}}, j={{j}}, count={{count}}
  {% endfor -%}
{% endfor -%}
""").render(outer_items=outer_items,
            inner_items=inner_items,
            num_outer=len(outer_items))

Ausgabe:

i=a, j=x, count=0
  i=a, j=y, count=1
  i=a, j=z, count=2
  i=b, j=x, count=3
  i=b, j=y, count=4
  i=b, j=z, count=5
  i=c, j=x, count=6
  i=c, j=y, count=7
  i=c, j=z, count=8

Um Anwendungsfälle wie dieser, ich habe ein kleines Umgebung Filter, das zählt Vorkommen eines Schlüssels.

zu lösen

Hier ist de-Code (mit doc-Test) von myfilters.py:

#coding: utf-8
from collections import defaultdict

from jinja2 import environmentfilter
from jinja2.utils import soft_unicode

@environmentfilter
def inc_filter(env, key, value=1, result='value', reset=False):
    """
    Count ocurrences of key.
    Stores the counter on Jinja's environment.
        >>> class Env: pass
        >>> env = Env()
        >>> inc_filter(env, 'x')
        1
        >>> inc_filter(env, 'x')
        2
        >>> inc_filter(env, 'y')
        1
        >>> inc_filter(env, 'x')
        3
        >>> inc_filter(env, 'x', reset=True)
        1
        >>> inc_filter(env, 'x')
        2
        >>> inc_filter(env, 'x', value=0, reset=True)
        0
        >>> inc_filter(env, 'x', result=None)
        >>> inc_filter(env, 'x', result=False)
        u''
        >>> inc_filter(env, 'x', result='key')
        'x'
        >>> inc_filter(env, 'x')
        4
    """
    if not hasattr(env, 'counters'):
        env.counters = defaultdict(int)

    if reset:
        env.counters[key] = 0

    env.counters[key] += value

    if result == 'key':
        return key
    elif result == 'value':
        return env.counters[key]
    elif result == None:
        return None
    else:
        return soft_unicode('')


## Module doctest
if __name__ == '__main__':
    import doctest
    doctest.testmod()    

Setup Ihre Umgebung unserer eigenen Filter Registrierung:

#coding: utf-8
from jinja2 import Environment, FileSystemLoader
from myfilters import inc_filter

env = Environment(loader=loader=FileSystemLoader('path'))
env.filters['inc'] = inc_filter

t = env.get_template('yourtemplate.txt')

items = [
    ['foo', 'bar'],
    ['bax', 'quux', 'ketchup', 'mustard'],
    ['bacon', 'eggs'],
    ]

res = t.render(items=items)

Und auf die Vorlage, verwenden Sie es wie folgt aus:

{% for group in items -%}
  {% for item in group -%}
    item={{ item }}, count={{ 'an_identifier'|inc }}
  {% endfor -%}
{% endfor -%}

... welche druckt:

item=foo, count=0
  item=bar, count=1

item=bax, count=2
  item=quux, count=3
  item=ketchup, count=4
  item=mustard, count=5

item=bacon, count=6
  item=eggs, count=7

Es gibt builtin globale Funktion Cycler () Bereitstellung Schleife unabhängigen Wert Radfahren. Mit der gleichen Idee können Sie Ihre eigene counter() Funktion wie folgt definiert werden:

env=Environment(...) # create environment
env.globals['counter']=_Counter # define global function
env.get_template(...).render(...) # render template

Hier ist die Klasse, die Geräte die Funktion:

class _Counter(object):
  def __init__(self, start_value=1):
    self.value=start_value

  def current(self):
    return self.value

  def next(self):
    v=self.value
    self.value+=1
    return v

Und hier ist, wie es zu benutzen:

{% set cnt=counter(5) %}
item #{{ cnt.next() }}
item #{{ cnt.next() }}
item #{{ cnt.next() }}
item #{{ cnt.next() }}

Es ist Gonna zu machen:

item #5
item #6
item #7
item #8

Keine Notwendigkeit, einen Zähler hinzuzufügen. Sie können die äußere Schleife-Index wie folgt zugreifen:

{% for i in 'a', 'b', 'c' -%}
  {% set outerloop = loop %}
  {% for j in 'x', 'y', 'z' -%}
    i={{i}}, j={{j}}, count={{outerloop.index0 * loop|length + loop.index0}}
  {% endfor -%}
{% endfor -%}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top