Rendering a python dict in Jinja2 / Werkzeug

六月ゝ 毕业季﹏ 提交于 2019-11-27 15:42:10

问题


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.


回答1:


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 %}



回答2:


Please note that dict.items() method is exists in both Python 2 and Python 3. But the method gives no warranties about the order items contained in dictionary are being iterated. This is why it could make more sense for this example to use a list of dictionaries instead of a dictionary of dictionaries like you said above.




回答3:


One approach is to cleanly separate processing logic from the HTML. Thus, put HTML in a separate file, such as, top.reddit.html. But content within the HTML is dynamic since it's pulled from Reddit. So we use Jinja2 as the templating engine. This implies that top.reddit.html is just the template but not the final content to be served.

top.reddit.html (showing only the dynamic rows here for brevity):

{% for item in data %}
<tr>
  <td width="0%">&nbsp;</td>
  <td>{{item["date"]}}, {{item["title"]}}<br>{{item["teaser"]}}</td>
  <td width="0%">&nbsp;</td>
</tr>
{% endfor %}

Python code to render the template (tested with Python 3.5.6, Jinja2 2.10):

import jinja2

# For illustration: list of dict
top_posts = [
    {'date': '06 Jun, 11:40AM', 'title': 'Title 1 goes here',  'teaser': 'One blah blah blah...'},
    {'date': '05 Jun, 04:50PM', 'title': 'Title 2 goes here',  'teaser': 'Two blah blah blah...'},
    {'date': '05 Jun, 09:60AM', 'title': 'Title 3 goes here',  'teaser': 'Three blah blah blah...'}
]

loader = jinja2.FileSystemLoader(searchpath="./")
jenv = jinja2.Environment(loader=loader)
template = jenv.get_template('top.reddit.html')
htmlout = template.render(data=top_posts)
print(htmlout)


来源:https://stackoverflow.com/questions/19141073/rendering-a-python-dict-in-jinja2-werkzeug

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!