J'essaie d'écrire un modèle d'arbre très simple dans Jinja2, en utilisant quelques objets personnalisés avec des méthodes spéciales surchargées (getattr, getitem, etc.) Cela semble simple, et la marche équivalente de l'arbre en Python fonctionne bien, mais il y a quelque chose sur la façon dont la récursion de Jinja fonctionne que je ne comprends pas. Le code est présenté ci-dessous :
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)
Le modèle lève une exception comme si la récursion n'avait pas eu lieu. L'appel interne est effectué, mais d'une manière ou d'une autre, la référence à 'category' fait toujours référence au parent. Que se passe-t-il ici ? Il doit y avoir quelque chose de très fondamental qui m'échappe sur la façon dont ces modèles récursifs sont censés fonctionner. (Ou quelque chose de fondamentalement stupide que je fais et que je ne vois pas.