user2839288 user2839288 - 5 months ago 16
Python Question

Rendering a python dict in Jinja2 / Werkzeug

I'm playing with a url shortener (basing it on the Shortly demo app from Werkzeug).

I have a dict like this -

('1', {'target': 'http://10.58.48.103:5000/', 'clicks': '1'})
('3', {'target': 'http://slash.org', 'clicks': '4'})
('2', {'target': 'http://10.58.48.58:5000/', 'clicks': '1'})
('5', {'target': 'http://de.com/a', 'clicks': '0'})


which is returned in url_list and used by render_template

def on_list_urls(self, request):
url_list = self.get_urls()
return self.render_template('list_urls.html',
url_list = url_list
)


the template list_urls is pretty simple -

{% extends "layout.html" %}
{% block title %}List URLs{% endblock %}
{% block body %}
<h2>List URLs</h2>
<ul id="items">
{% for item in url_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>

{% endblock %}


Thing is, I can't seem to access the items in the dict.

The line

<li>{{ item }}</li>


is where I'm focussing attention. As above, I get a list of the keys in the dict.

<li>{{ item["target"] }}</li>


returns nothing. None of the
{{ user.url }}">{{ user.username }}
type stuff in the docs seems to work.

Ideas please? Newbie - be gentle. Thanks.

Update

Thanks for the responses.

Ewan's answer works, but uses a list of dicts. I want to pass a dict and render that (because I want a non-integer index of items). Does Jinja do that?

Also - I mis-represented url_list. It's more like this -

{'a': {'target': 'http://testing.com/test', 'clicks': '0'},
'1': {'target': 'http://10.58.48.103:5000/', 'clicks': '1'},
'3': {'target': 'http://slash.org', 'clicks': '4'},
'2': {'target': 'http://10.58.48.58:5000/', 'clicks': '1'}}


Further experimentation - passing a dict produces an error about a list object.

{% for key in url_list.iteritems() %}

UndefinedError: 'list object' has no attribute 'iteritems'


Thanks again.

Still baffled by why it thought I was passing a list but got it working now.

{% for key, value in url_list.iteritems() %}
<li>{{ key }} - {{ value["target"] }} - {{ value["clicks"] }}</li>


prints out everything. Many thanks.

Answer

Your url_list should look like this:

url_list = [{'target': 'http://10.58.48.103:5000/', 'clicks': '1'}, 
            {'target': 'http://slash.org', 'clicks': '4'},
            {'target': 'http://10.58.48.58:5000/', 'clicks': '1'},
            {'target': 'http://de.com/a', 'clicks': '0'}]

Then using:

<li>{{ item["target"] }}</li> 

in your template will work.

Edit 1:

Your template think you're passing a list in, so are you sure you're passing in your original dict and not my above list?

Also you need to access both a key and a value in your dictionary (when you're passing a dictionary rather than a list):

Python 2.7

{% for key, value in url_list.iteritems() %}
    <li>{{ value["target"] }}</li> 
{% endfor %}

Python 3

{% for key, value in url_list.items() %}
    <li>{{ value["target"] }}</li> 
{% endfor %}
Comments