Как получить доступ к элементу словаря в шаблоне Django?

181

Я хотел бы распечатать количество голосов, которые получил каждый выбор. У меня есть этот код в шаблоне:

{% for choice in choices %}
    {{choice.choice}} - {{votes[choice.id]}} <br />
{% endfor %}

votesэто просто словарь, в то время choicesкак это модельный объект.

Это вызывает исключение с этим сообщением:

"Could not parse the remainder"
Mohamed
источник

Ответы:

63

Чтобы повторить / расширить комментарий Джеффа, я думаю, что вы должны стремиться к простому свойству в классе Choice, которое вычисляет количество голосов, связанных с этим объектом:

class Choice(models.Model):
    text = models.CharField(max_length=200)

    def calculateVotes(self):
        return Vote.objects.filter(choice=self).count()

    votes = property(calculateVotes)

И тогда в вашем шаблоне вы можете сделать:

{% for choice in choices %}
    {{choice.choice}} - {{choice.votes}} <br />
{% endfor %}

Тег шаблона, IMHO, немного излишним для этого решения, но это тоже не страшное решение. Цель шаблонов в Django - изолировать вас от кода в ваших шаблонах и наоборот.

Я попробую описанный выше метод и посмотрю, какой SQL генерирует ORM, так как я не уверен, что он будет предварительно кэшировать свойства и просто создаст отбор для свойства или будет итеративно По требованию запустите запрос для подсчета голосов. Но если он генерирует жестокие запросы, вы всегда можете заполнить свойство по вашему мнению данными, которые вы собрали самостоятельно.

Джон Юарт
источник
спасибо @john ewart, ваше решение сработало для меня. Я новичок в django и python и не могу понять, как получить sql, сгенерированный ORM.
Мохамед
Вы можете найти ответ на этот вопрос здесь: docs.djangoproject.com/en/dev/faq/models/… Это довольно просто, на самом деле и может быть отображено в вашем шаблоне или зарегистрировано с помощью средства ведения журнала, но вы должны не забудьте включить DEBUG, чтобы это работало.
Джон Эварт
это решение идеально подходит для решения проблемы с шаблонами django + google app engine. Хотел бы я проголосовать за тебя дважды.
Conrad.Dean
5
Хотя это работает, это не очень эффективно. Он выполняет sql запросы в цикле (чего следует избегать). Создать свой собственный тег для поиска в режиме dict легко: @ register.filter def lookup (d, key): если d и isinstance (d, dict): вернуть d.get (key)
dalore
Создание класса - это слишком много. лучше структурированный словарь в сочетании с .itemsвызовом (как показано в одном из других ответов) является гораздо более простым решением.
Загс
285
choices = {'key1':'val1', 'key2':'val2'}

Вот шаблон:

<ul>
{% for key, value in choices.items %} 
  <li>{{key}} - {{value}}</li>
{% endfor %}
</ul>

По сути, .itemsэто ключевое слово Django, которое разбивает словарь на список (key, value)пар, как и метод Python .items(). Это позволяет выполнять итерацию по словарю в шаблоне Django.

russian_spy
источник
@anacarolinats (и другие) просто убедитесь, что вы перебираете оба ключа, значение для choices.items. Это все еще должно работать.
OldTinfoil
В заключение! Спасибо!! : D
djGrill
поэтому в шаблонизаторе нельзя использовать (). Кстати спасибо Wotks для меня.
BlaShadow
6
Хорошее краткое решение вопроса. Для пояснения, itemsэто вызов метода Python для словаря, а не ключевое слово Django. Как указывает Алекс Мартелли, это в основном то же самое, что и iteritems. Как ответил Вильгельм, поиск по словарю занимает третье место по количеству точечных поисков. Если в вашем словаре есть элемент с именем 'items', вы получите это значение вместо списка кортежей. Чтобы проверить: добавьте {'items':'oops'}в свой словарь, и вы получите маркированный список букв от слова «упс»
cod3monk3y
1
Используйте collection.OrderedDict для управления порядком итерации
dnalow
186

Вы можете использовать точечную запись:

Поиск точек можно суммировать следующим образом: когда система шаблонов встречает точку в имени переменной, она пытается выполнить следующий поиск в следующем порядке:

  • Поиск по словарю (например, foo ["bar"])
  • Поиск атрибутов (например, foo.bar)
  • Вызов метода (например, foo.bar ())
  • Поиск по индексу списка (например, foo [2])

Система использует первый тип поиска, который работает. Это логика короткого замыкания.

Вильгельм
источник
44
В его случае выбор является переменной. Выполнение .choice будет искать значение для ключа «выбор», а не значение для выбора ключа.
IBZ
+1 за информацию, хотя вопрос был своего рода вопросом «угадай, что я думаю». Спасибо, Вильгельм.
eficker
1
Это даже работает с вложенными словарями. Код Python: Код my_dict[1][2]шаблона:my_dict.1.2
djsmith
2
@ JCLeitão Потому что правильная версия d.key.1- обратите внимание на вторую.
Izkata
3
Проверьте документы по этому вопросу, хотя ... из "1.6 docs.djangoproject.com/en/1.6/topics/templates/#variables ": обратите внимание, что «bar» в выражении шаблона, таком как {{foo.bar}}, будет интерпретироваться в виде литеральной строки и без использования значения переменной «bar», если она существует в контексте шаблона.
Jamesc
25

Вам нужно найти (или определить) тег шаблона 'get', например, здесь .

Определение тега:

@register.filter
def hash(h, key):
    return h[key]

И это используется как:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}
Нед Бэтчелдер
источник
3
рассмотреть h.get(key,'default_value')из-за KeyError
полуомант
9

Используйте элементы словаря:

{% for key, value in my_dictionay.items %}
  <li>{{ key }} : {{ value }}</li>
{% endfor %}
Прияншу Чаухан
источник
6

имя фильтра django_template_filter get_value_from_dict

{{ your_dict|get_value_from_dict:your_key }}
Ник Корольков
источник
6

Аналогично ответу @russian_spy:

<ul>
{% for choice in choices.items %} 
  <li>{{choice.0}} - {{choice.1}}</li>
{% endfor %}
</ul>

Это может подойти для разбивки более сложных словарей.

Адам Старр
источник
3

В идеале вы должны создать метод для объекта выбора, который окажется в голосовании, или создать связь между моделями. Тег шаблона, который выполнил поиск по словарю, тоже подойдет.

Джефф Обер
источник