Pergunta

Estou tentando escrever um modelo muito simples de caminhada em árvore em Jinja2, usando alguns objetos personalizados com métodos especiais sobrecarregados (getattr, getItem, etc.), parece direto, e a caminhada equivalente a python da árvore funciona bem, mas há algo Sobre a maneira como a recursão de Jinja funciona que eu não entendo. O código é mostrado abaixo:

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)

O modelo está levantando uma exceção como se a recursão não fosse realmente. A chamada interna é feita, mas de alguma forma a referência à 'categoria' ainda se refere aos pais. O que dá aqui? Deve haver algo muito fundamental sobre como esses modelos recursivos devem funcionar. (Ou algo muito fundamentalmente bobo que estou fazendo que simplesmente não consigo ver.

Foi útil?

Solução

Como vejo no seu código, você entende recursivo corretamente, exceto uma coisa: ele substitui o iterable na declaração for, mas não atualiza a variável (category no seu código) originalmente usado nele. Assim, você aninhou loop itera através das crianças, mas set Pesquisas de tags no original category, nenhum passou para o loop().

Eu sugiro mudar __iter__() método para retornar self.items.iteritems() e modelo 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>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top