Looping over a tuple in jinja2

jinja2, python

Solution

You should change the data structure. Complex data processing like this belongs in Python not in templates. You'll find there probably are ways to hack it in Jinja 2 (though probably not in Django's templates). But you should not do that.

Instead create a nested data structure

dates = [[d1, m1, y1], ..., [dn, mn, yn]]
datedict = {}
for d, m, y in dates:
    yeardict = datedict.setdefault(y, {})
    monthset = yeardict.setdefault(m, set())
    monthset.add(d)

nested_dates = [(y, list((m, sorted(days))
                         for m, days in sorted(yeardict.items())))
                for y, yeardict in sorted(datedict.items())]

so if `dates` starts out as

dates = [[1, 2, 2013], [5, 2, 2013], [1, 3, 2013]]

`nested_dates` will end up as

[(2013, [(2, [1, 5]), (3, [1])])]

so you can do

{% for year in nested_dates %}
    <li class="year">
        <a href="#">{{year.0}}</a>
        <ul>
        {% for month in year.1 %}
            <li class="month">
                <a href="#">{{month.0}}</a>
                <ul>
                {% for day in month.1 %}
                    <li class="day">{{day}}</li>
                {% endfor %}
                </ul>
            </li>
        {% endfor %}
        </ul>
    </li>
{% endfor %}

NB: That list comprehension is pushing the limits of what you should do in a list comprehension, if you want your code to make any sense later on, or to another programmer. So you could write it more clearly as:

nested_dates = []
for y, yeardict in sorted(datedict.items()):
    yearlist = []
    for m, days in sorted(yeardict.items()):
        yearlist.append((m, sorted(days)))
    nested_dates.append((y, yearlist))

In general the answer to any question that begins "How do I get my templating system to output data in this structure", is "Give it data in that structure".

Problem

I have a list of date in format ['DD', 'MM', 'YYYY'], and saved it to a tuples called listdates [['DD', 'MM', 'YYYY'], ['DD', 'MM', 'YYYY']] I wanted to make a html like this ``` <li class="year"> <a href="#">2013</a> <ul> <li class="month"> <a href="#">11</a> <ul> <li class="day">01</li> <li class="day">02</li> <li class="day">03</li> ... </ul> </li> <li class="month"> <a href="#">12</a> <ul> <li class="day">01</li> <li class="day">02</li> ... </ul> </li> </ul> </li> ``` I've tried this for a day but hasn't found a way. Is there an easy way to do this ? or should I change the data structure ?

Original source