2009-10-13 12 views
8

Estoy tratando de escribir una plantilla muy simple para caminar sobre árboles en jinja2, usando algunos objetos personalizados con métodos especiales sobrecargados (getattr, getitem, etc.) Parece sencillo, y el camino de python equivalente funciona bien, pero hay algo sobre la forma en que funciona la recursión de Jinja que no entiendo. El código se muestra a continuación:¿Cómo funciona realmente la etiqueta "recursiva" de 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) 

La plantilla genera una excepción como si la recursión en realidad no tuviera lugar. La llamada interna se realiza, pero de alguna manera la referencia a 'categoría' todavía se refiere al padre. ¿Qué da aquí? Debe haber algo muy fundamental que me falta acerca de cómo se supone que estas plantillas recursivas funcionan. (O algo muy fundamentalmente tonto que estoy haciendo que simplemente no puedo ver.

+1

Debe publicar en la lista de correo de pocoo-libs. Armin (creador de Jinja) verá tu publicación allí. http://groups.google.com/group/pocoo-libs/topics –

Respuesta

7

Como veo en tu código, entiendes recursivo correctamente, excepto una cosa: reemplaza iterable en la declaración for, pero doesn ' actualización de la variable t (category en su código) utilizado originalmente en el mismo. por lo tanto, itera anidados bucle a través de los niños, pero set operaciones de búsqueda de etiquetas en el original category, ninguno pasa al loop().

sugiero cambiar __iter__() método para devolver self.items.iteritems() y plantilla para:

<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> 
Cuestiones relacionadas