Flask / Jinja2 – Iterando sobre diccionarios nesteds

Estoy tratando de mostrar el contenido y la estructura de un diccionario en forma de un montón de listas anidadas no ordenadas.

Los datos que he logrado reunir se parecen a esto,

{'.': {'walk.py': None, 'what.html': None, 'misc': {}, 'orders': {'order1.html': None, 'more': {'stuff.html': None}}}} 

que representa este árbol de directorios,

 .: misc/ orders/ walk.py what.html ./misc: ./orders: more/ order1.html ./orders/more: stuff.html 

¿Cómo puedo hacer una iteración sobre esto utilizando la syntax de Jinja2? ¿Hay una mejor manera de hacer esto?

Gracias de antemano.

EDIT: me siento estúpido. Después de buscar una solución otra vez, descubrí exactamente lo que estaba buscando. Supongo que mi google-fu no fue realmente conmigo el primer bash. Aquí está…

Usando el modificador recursive del bucle for (ejemplo tomado de la documentación):

 
    {%- for item in sitemap recursive %}
  • {{ item.title }} {%- if item.children -%} {%- endif %}
  • {%- endfor %}

ACTUALIZAR

Aquí hay algo que se me ocurrió:

 from jinja2 import Template x = Template("""{%- for key, value in tree.iteritems() recursive %} {{ '--' * (loop.depth-1) }}{{ key }} {%- if value is mapping -%}/{{ loop(value.iteritems()) }}{%- endif -%} {%- endfor %} """) tree = {'.': { 'walk.py': None, 'what.html': None, 'misc': {}, 'orders': { 'order1.html': None, 'more': { 'stuff.html': None } } }} print x.render(tree=tree) 

Salida:

 ./ --walk.py --what.html --misc/ --orders/ ----order1.html ----more/ ------stuff.html 

(Los guiones en el código Jinja2 (por ejemplo, {%- ... -%} son para el control de espacios en blanco . Juega con eso.)

¿Por qué no solo un bucle nested?

en tus vistas.py:

 def index(request): context={'main1':{'sub1','sub2','sub3'},'main2':{'sub1','sub2'}} return render(request,'index.html',context) 

en su index.html:

 {% for key1,val in context.items %} 

{{ key1 }}

    {% for key2 in val.items %}
  • {{key2}}
  • {% endfor %}
{% endfor %}

Primero organiza los datos:

 a = {'.': {'walk.py': None, 'what.html': None, 'misc': {}, 'orders': {'order1.html': None, 'more': {'stuff.html': None}}}} from collections import defaultdict def f(data, path): for k,v in data.iteritems(): if v is None: yield path,k else: yield path,k+"/" for k in f(v,path+k+"/"): yield k def process_data(): collect = defaultdict(list) for p in f(a,""): if p[0]: collect[p[0][:-1]].append(p[1]) return collect 

Ahora si corres:

 data = process_data() for k in data.keys(): print k,data[k] 

Usted obtiene:

 ./orders ['order1.html', 'more/'] ./orders/more ['stuff.html'] . ['walk.py', 'what.html', 'misc/', 'orders/'] 

Eso es todo lo que necesitas para renderizar. La plantilla debe ser algo como:

 {% for k in sitemap.keys()|sort -%} {{ k }}:
{% for v in sitemap[k] %} {{ v }} {%- endfor %}
{%- endfor %}

y la convocatoria para la prestación:

 @app.route("/") def hello(): return render_template('temp.html',sitemap=process_data()) 

Que en mi prueba se traduce como:

 .:
walk.py what.html misc/ orders/
./orders:
order1.html more/
./orders/more:
stuff.html