2009-10-13 10 views
8

Ich versuche, eine sehr einfache, Baum-Walking-Vorlage in Jinja2 zu schreiben, mit einigen benutzerdefinierten Objekten mit überladenen speziellen Methoden (getattr, getitem, etc) Es scheint einfach, und die entsprechende Python Walk des Baumes funktioniert gut, aber Es gibt etwas über die Art, wie Jinjas Rekursion funktioniert, die ich nicht verstehe. Der Code ist unten dargestellt:Wie funktioniert das "rekursive" Tag von Jinja2?

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 Aufruf wird gemacht, aber irgendwie bezieht sich der Verweis auf "Kategorie" immer noch auf den Elternteil. Was gibt es hier? Es muss etwas sehr fundamentales fehlen, was die rekursiven Vorlagen angeht. (Oder etwas sehr grundlegend albernes, dass ich tue, dass ich einfach nicht sehen kann.

+1

Sie sollten auf der pocoo-libs-Mailingliste posten. Armin (Schöpfer von Jinja) wird deinen Beitrag dort sehen. http://groups.google.com/group/pocool-libs/topics –

Antwort

7

Wie ich aus Ihrem Code verstehe Sie rekursiv korrekt, mit einer Ausnahme: Es ersetzt iterable in der for-Anweisung, aber doesn ' t Update Variable (category in Ihrem Code), die ursprünglich in sie verwendet wird. Somit Sie verschachtelte Schleife wiederholt durch Kinder, aber set Tag Lookups in original category, nicht ein auf die loop() geben.

ich schlage vor Wechsel __iter__() Methode self.items.iteritems() zurückzukehren und Vorlage zu:

<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> 
Verwandte Themen