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


181

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

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

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

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

"Could not parse the remainder"

Ответы:


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.


@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
полуомант



6

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

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

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


3

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.