Jeremy Weirich Jeremy Weirich - 3 months ago 9
Python Question

'for' statements should use the format 'for x in y': while iterating over value retrieved from dictionary using django template

I have a context dictionary entry

objectives
that maps objective query objects to a list of tests that belong to that objective. Example code:

objectives = Objective.objects.filter(requirement=requirement)
context_dict["requirements"][requirement] = objectives
for objective in objectives:
tests = Test.objects.filter(objective=objective)
context_dict["objectives"][objective] = tests


In my django html template, I iterate over objectives and display them. I then want to iterate over the tests that belong to these objectives. When I do this:

{% for test in {{ objectives|get_item:objective }} %}


I get a
TemplateSyntaxError: 'for' statements should use the format 'for x in y':


In the application/templatetags directory, I have:

from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)


If instead I make
{{ objectives|get_item:objective }}
a JS variable, I see that it does indeed produce a list, which I should be able to iterate over. Of course, I can't mix JS variables and the django template tags, so this is only for debugging:

var tests = {{ objectives|get_item:objective }}

var tests = [<Test: AT399_8_1>, <Test: AT399_8_2>, <Test: AT399_8_3>, <Test: AT399_8_4>, <Test: AT399_8_5> '...(remaining elements truncated)...']


How do I iterate over this list in the django template tag?

Answer

You cannot user {{...}} inside the {%...%}

What you can try is changing your filter to an assignment tag and using that value in the loop

@register.assignment_tag
def get_item(dictionary, key):
    return dictionary.get(key)  

And then in your template use it as

{% get_item objectives objective as tests %}
{% for test in test %}  
    ....
{% endfor %}

Instead of all this if your models are proper with foreign keys I would do something like

{% for objective in requirement.objective_set.all %}  
    {% for test in objective.test_set.all %}  
        ....
    {% endfor %}  
{% endfor %}  

In my context I would pass only the requirement