Рендеринг python dict в Jinja2/Werkzeug

Я играю с сокращателем URL (на основе демонстрационного приложения Shortly от Werkzeug).

У меня есть такой диктант -

('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'})

который возвращается в url_list и используется render_template

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

шаблон list_urls довольно прост -

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

Дело в том, что я не могу получить доступ к элементам в dict.

Линия

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

это то, на чем я сосредоточил внимание. Как и выше, я получаю список ключей в dict.

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

ничего не возвращает. Кажется, что ни один из элементов типа {{ user.url }}›{{ user.username }} в документах не работает.

Идеи пожалуйста? Новичок - будь нежным. Спасибо.

Обновить

Спасибо за ответы.

Ответ Эвана работает, но использует список диктовок. Я хочу передать dict и отобразить его (потому что мне нужен нецелочисленный индекс элементов). Джинджа так делает?

Кроме того, я неверно представил url_list. Это больше похоже на это -

{'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'}}

Дальнейшие эксперименты - передача dict выдает ошибку об объекте списка.

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

UndefinedError: «объект списка» не имеет атрибута «iteritems»

Спасибо еще раз.

Все еще озадачен тем, почему он думал, что я передаю список, но теперь он работает.

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

распечатывает все. Большое спасибо.


person user2839288    schedule 02.10.2013    source источник
comment
Для меня это не похоже на диктовку... Это список кортежей с диктовками в качестве второго элемента.   -  person Ewan    schedule 02.10.2013


Ответы (3)


Ваш url_list должен выглядеть так:

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'}]

Затем с помощью:

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

в вашем шаблоне будет работать.

Редактировать 1:

Ваш шаблон думает, что вы передаете список, поэтому вы уверены, что передаете свой исходный список, а не мой список выше?

Также вам необходимо получить доступ к key и value в вашем словаре (когда вы передаете словарь, а не список):

Питон 2.7

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

Питон 3

{% for key, value in url_list.items() %}
    <li>{{ value["target"] }}</li> 
{% endfor %}
person Ewan    schedule 02.10.2013
comment
В Python 3 вашим url_list.iteritems будет url_list.items() (и вам нужны круглые скобки, чтобы вызвать его). - person Noumenon; 22.06.2016
comment
@Noumenon - хороший момент, интересно, что редактирование сообщества удалило скобки, но я снова добавлю и включу пример Python 3. Спасибо что подметил это. - person Ewan; 22.06.2016
comment
Благодарю вас! Это мне очень помогло! - person Aker666; 24.04.2019

Один из подходов заключается в четком отделении логики обработки от HTML. Таким образом, поместите HTML в отдельный файл, например, top.reddit.html. Но содержимое в HTML является динамическим, поскольку оно взято из Reddit. Поэтому мы используем Jinja2 в качестве шаблонизатора. Это означает, что top.reddit.html — это всего лишь шаблон, а не окончательный контент, который будет обслуживаться.

top.reddit.html (здесь для краткости показаны только динамические строки):

{% 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 для рендеринга шаблона (проверено с 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)
person coder.in.me    schedule 06.06.2019

Обратите внимание, что метод dict.items() существует как в Python 2, так и в Python 3. Но этот метод не дает никаких гарантий того, что элементы порядка, содержащиеся в словаре, повторяются. Вот почему в этом примере может иметь смысл использовать список словарей вместо словаря словарей, как вы сказали выше.

person Federico Ressi    schedule 02.02.2018