Frage

Ich versuche, eine sehr einfache, Tree-Walking-Vorlage in jinja2 zu schreiben, einige benutzerdefinierten Objekten mit überladenen speziellen Methoden (getattr, getitem, usw.) Es scheint einfach, und der äquivalente Python Fuß des Baumes funktioniert gut, aber es gibt etwas über die Art und Weise, dass Jinja Rekursion funktioniert, dass ich nicht verstehe. Der Code ist unten dargestellt:

from jinja2 import Template

class Category(object):

    def __init__(self, name):
        self.name = name
        self.items = {}
        self.children = True

    def __iter__(self):
        return iter(self.items)

    def add(self, key, item):
        self.items[key] = item
        return item

    def __getitem__(self, item):
        return self.items[item]

    def __getattr__(self, attr):
        try:
            return self.items[attr]
        except KeyError:
            raise AttributeError(attr)

    def __str__(self):
        return "<Category '%s'>" % self.name

template = '''
<saved_data>
{% for key in category recursive %}
    {% set item = category[key] %}
    {% if item.children %}
        <category name="{{key}}">
            {{ loop(item) }}
        </category>
    {% else %}
        <item name="{{ key }}" value="{{ item }}" />
    {% endif %}
{% endfor %}
</saved_data>
'''

b = Category('root')
c = b.add("numbers", Category('numbers'))
c.add("one", 1)
c.add("two", 2)
c.add("three", 3)
d = b.add("letters", Category('letters'))
d.add('ay','a')
d.add('bee','b')
d.add('cee','c')
e = d.add("bools", Category('bools'))
e.add('tru', True)
e.add('fals', False)

def walk(c, depth=0):
    for key in c:
        item = c[key]
        print (' '*depth) + str(item)
        if hasattr(item, 'children'):
            walk(item, depth+3)
print "Python walking the tree:"
walk(b)

print ""
print "Jinja2 Walking the tree:"
t = Template(template)
print t.render(category = b)

Die Vorlage wird eine Ausnahme ausgelöst, als ob die Rekursion eigentlich gar nicht stattfinden. Der innere Ruf gemacht, aber irgendwie die Bezugnahme auf ‚Kategorie‘ bezieht sich immer noch auf die Mutter. Was gibt hier? Es muss etwas sehr grundlegender Bedeutung sein Ich vermisse, wie diese rekursive Vorlagen arbeiten sollen. (Oder etwas ganz grundsätzlich dumm, dass ich tue, dass ich einfach nicht sehen.

War es hilfreich?

Lösung

Wie ich aus dem Code sehen Sie richtig verstanden rekursiv, bis auf einer Sache: es iterable in dem for-Anweisung nicht ersetzt, aber keine Variable (category in Ihrem Code) aktualisieren ursprünglich darin verwendet. So iteriert Sie verschachtelte Schleife durch Kinder, aber set Tag Lookups in original category, nicht ein auf die loop() weitergegeben.

Ich schlage vor Wechsel __iter__() Methode zur Rückkehr self.items.iteritems() und Vorlage:

<saved_data>
{% for key, item in category recursive %}
        {% if item.children %}
                <category name="{{key}}">
                        {{ loop(item) }}
                </category>
        {% else %}
                <item name="{{ key }}" value="{{ item }}" />
        {% endif %}
{% endfor %}
</saved_data>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top