Reputation: 1253
Running into a strange problem with Django's template, and being n00b I don't even know how to debug a template...
PROBLEM: variables of a type list
somehow stopped being a list
when passed into the template.
In my view, I have a bunch of variables passed to the template that are a dictionary of lists. Here's the code,
VIEW
project_image_design = {}
for p in projects:
project_image_design[p.id] = []
images = UploadedImage.objects.filter(project=p, image_type=UploadedImage.DESIGN)
for i in images:
project_image_design[p.id].append(i)
Here's the context. I have projects, each contains images. I created a dictionary, where the keys are the project id, and the value is a list of images associated with that project.
However, when I use this in the template, things go wrong,
TEMPLATE
{% for p in projects %}
<div class="row">
{% for list in project_image_design|get_item:p.id %}
{% for i in list %}
<div class="col-md-2"><img src = "{% get_static_prefix %}media/{{ i.filename }}"></div>
{% endfor %}
{% endfor %}
</div>
{% endfor %}
So in the template, I'm iterating through projects, then using the project's id (p.id
) to get the dictionary value, which is a list of images, and then iterating through that. The fancy get_item
tag is just a way to access dictionary values through keys that not straight-forward variables (see: Django template how to look up a dictionary value with a variable).
Anyway, I get this error:
TypeError at /designer/my_projects/
'UploadedImage' object is not iterable
The error occurs on this line: {% for i in list %}
, which is the line where I'm iterating through the list of images I retrieved using my project's id.
What's going on here????
I double-checked via pdb in the view, it all checks out. The variable being passed is indeed a dictionary of lists, I put a type
on all the individual dictionary elements and they're all lists (like: type(project_image_design[1])
would return <class 'list'>
).
Also, at the moment, all the lists are of length 1. I'm wondering maybe the template sort of deflates lists that are size 1? That'd seem like a pretty weird thing to do, probably not the reason.
Any help would be appreciated.
Also, how do I debug templates the way I can debug Python code? Like stepping through and stuff? Is that even possible?
Upvotes: 0
Views: 742
Reputation: 599778
It hasn't stopped being a list. But you have two nested for loops: you iterate through the items you get from the dictionary - confusingly calling each item list
- and then attempt to iterate again through items in that "list". But the inner loop makes no sense: you should be doing simply:
{% for i in project_image_design|get_item:p.id %}
<div class="col-md-2"><img src = "{% get_static_prefix %}media/{{ i.filename }}"></div>
{% endfor %}
I'd also point out that your view logic is over-complicated. It could be reduced to simply this:
for p in projects:
project_image_design[p.id] = UploadedImage.objects.filter(project=p, image_type=UploadedImage.DESIGN)
And in fact it could be simplified even further: you don't need the dictionary, or the get_item tag, at all. Instead, provide a method on Project called something like design_images
which just returns the images of that type:
def design_images(self):
return self.uploadedimage_set.filter(image_type=UploadedImage.DESIGN)
and removing the dictionary logic from the view altogether, and now your template can just be:
{% for p in projects %}
<div class="row">
{% for i in p.design_images %}
<div class="col-md-2"><img src = "{% get_static_prefix %}media/{{ i.filename }}"></div>
{% endfor %}
</div>
{% endfor %}
Upvotes: 3