225

I would like to print out the number of votes that each choice got. I have this code in a template:

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

votes is just a dictionary while choices is a model object.

It raises an exception with this message:

"Could not parse the remainder"
daaawx
  • 3,273
  • 2
  • 17
  • 16
Mohamed
  • 3,420
  • 7
  • 28
  • 31

9 Answers9

348
choices = {'key1':'val1', 'key2':'val2'}

Here's the template:

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

Basically, .items is a Django keyword that splits a dictionary into a list of (key, value) pairs, much like the Python method .items(). This enables iteration over a dictionary in a Django template.

daaawx
  • 3,273
  • 2
  • 17
  • 16
russian_spy
  • 6,465
  • 4
  • 30
  • 26
  • @anacarolinats (and others) just make sure you iterate over both the key,value for choices.items. It should still work. – OldTinfoil Jan 04 '13 at 11:52
  • so in the template engine can't use ( ). BTW Thanks wotks for me. – BlaShadow Nov 04 '13 at 18:40
  • 7
    Nice concise solution to the question. To clarify, `items` is a Python method call on the dictionary, not a Django keyword. As [Alex Martelli points out](http://stackoverflow.com/a/3744713/1174169) it's basically the same as `iteritems`. As Wilhelm answered, the dictionary lookup is 3rd in precedence for dot lookups. If you have an item in your dictionary named `'items'`, you'll get that value back instead of a list of tuples. To test: add `{'items':'oops'}` to your dictionary and you'll get a bulleted list of letters from the word 'oops' – cod3monk3y Nov 08 '13 at 01:53
  • 1
    Use collections.OrderedDict to control the order of the iteration – dnalow Jan 07 '15 at 11:35
  • 1
    This should be the accepted answer. Simple and straightforward! – Nikolai Tschacher Oct 28 '15 at 13:16
227

you can use the dot notation:

Dot lookups can be summarized like this: when the template system encounters a dot in a variable name, it tries the following lookups, in this order:

  • Dictionary lookup (e.g., foo["bar"])
  • Attribute lookup (e.g., foo.bar)
  • Method call (e.g., foo.bar())
  • List-index lookup (e.g., foo[2])

The system uses the first lookup type that works. It’s short-circuit logic.

Wilhelm
  • 6,506
  • 5
  • 30
  • 26
  • 50
    In his case choice is a variable. Doing .choice will look up the value for the key "choice" rather the value for the key choice. – ibz Jan 30 '11 at 09:35
  • 1
    +1 for the info, even though the question was kind of a "guess what I'm thinking" question. Thanks Wilhelm. – eficker Oct 25 '11 at 01:31
  • 4
    This even works with nested dictionaries. Python code: `my_dict[1][2]` Template code: `my_dict.1.2` – djsmith Jan 26 '12 at 20:39
  • What if the dictionary of lists, d = {key: [value1,value2]}. I'm not being able to use d.key1 to retrieve the list. Any idea why? – Jorge Leitao Nov 26 '12 at 08:04
  • 2
    @J.C.Leitão Because the correct version is `d.key.1` - note the second `.` – Izkata Apr 19 '13 at 19:42
  • 3
    Check the docs on this though... from "1.6 https://docs.djangoproject.com/en/1.6/topics/templates/#variables" : Note that “bar” in a template expression like {{ foo.bar }} will be interpreted as a literal string and not using the value of the variable “bar”, if one exists in the template context. – jamesc Dec 13 '13 at 18:00
67

To echo / extend upon Jeff's comment, what I think you should aim for is simply a property in your Choice class that calculates the number of votes associated with that object:

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

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

    votes = property(calculateVotes)

And then in your template, you can do:

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

The template tag, is IMHO a bit overkill for this solution, but it's not a terrible solution either. The goal of templates in Django is to insulate you from code in your templates and vice-versa.

I'd try the above method and see what SQL the ORM generates as I'm not sure off the top of my head if it will pre-cache the properties and just create a subselect for the property or if it will iteratively / on-demand run the query to calculate vote count. But if it generates atrocious queries, you could always populate the property in your view with data you've collected yourself.

Vishal Singh
  • 6,014
  • 2
  • 17
  • 33
John Ewart
  • 1,240
  • 1
  • 9
  • 6
  • thanks @john ewart, your solution worked for me. I am newbie to django and python and can't figureout how to get the sql that ORM generated. – Mohamed Aug 14 '09 at 08:27
  • You can find the answer to that bit over here: http://docs.djangoproject.com/en/dev/faq/models/#how-can-i-see-the-raw-sql-queries-django-is-running It's quite simple, actually and can be displayed in your template, or logged with a logging facility, but you have to remember to turn DEBUG on for this to work. – John Ewart Aug 14 '09 at 14:04
  • this solution is perfect for a problem I've been having with django templating + google app engine models. I wish I could vote you up twice. – Conrad.Dean May 07 '11 at 16:32
  • 6
    While it does work, it's not very efficient. It is doing sql queries in a loop (something you should avoid). Creating your own tag to do dict lookups is easy: @register.filter def lookup(d, key): if d and isinstance(d, dict): return d.get(key) – dalore Oct 30 '12 at 14:10
  • Creating a class is way too much overhead; a better structured dictionary, combined with the `.items` call (as illustrated in one of the other answers) is a far simpler solution. – Zags Feb 07 '14 at 23:08
  • Why choice.choice? Choice.Text not? – Timo Aug 02 '18 at 09:05
39

You need to find (or define) a 'get' template tag, for example, here.

The tag definition:

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

And it’s used like:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}
Sardathrion - against SE abuse
  • 17,269
  • 27
  • 101
  • 156
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • 5
    consider `h.get(key,'default_value')` because of KeyError – semiomant May 09 '17 at 14:27
  • 13 years later I still think this is the best solution to programmatic access to a dictionary from within a template - on the rare use-case that presents itself. – Djones4822 Aug 30 '22 at 02:22
10

django_template_filter filter name get_value_from_dict

{{ your_dict|get_value_from_dict:your_key }}
Nick Korolkov
  • 433
  • 6
  • 5
  • This requires the `sw-django-utils` library to be installed – simotek Oct 04 '22 at 02:45
  • In case someone wants to use this, you can incorporate this in your code base by registering your own custom template filter. This will mean you don't have to install the entire `sw-django-utils` dependency. How to register a custom template filter: https://docs.djangoproject.com/en/4.1/howto/custom-template-tags/ – vinayman Jan 09 '23 at 10:19
8

Similar to the answer by @russian_spy :

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

This might be suitable for breaking down more complex dictionaries.

Adam Starrh
  • 6,428
  • 8
  • 50
  • 89
3

Ideally, you would create a method on the choice object that found itself in votes, or create a relationship between the models. A template tag that performed the dictionary lookup would work, too.

Jeff Ober
  • 4,967
  • 20
  • 15
3

Could find nothing simpler and better than this solution. Also see the doc.

@register.filter
def dictitem(dictionary, key):
    return dictionary.get(key)

But there's a problem (also discussed here) that the returned item is an object and I need to reference a field of this object. Expressions like {{ (schema_dict|dictitem:schema_code).name }} are not supported, so the only solution I found was:

{% with schema=schema_dict|dictitem:schema_code %}
    <p>Selected schema: {{ schema.name }}</p>
{% endwith %}

UPDATE:

@register.filter
def member(obj, name):
    return getattr(obj, name, None)

So no need for a with tag:

{{ schema_dict|dictitem:schema_code|member:'name' }}
Nick Legend
  • 789
  • 1
  • 7
  • 21
-3

You could use a namedtuple instead of a dict. This is a shorthand for using a data class. Instead of

person = {'name':  'John', 'age':  14}

...do:

from collections import namedtuple
Person = namedtuple('person', ['name', 'age'])
p = Person(name='John', age=14)
p.name # 'John'

This is the same as writing a class that just holds data. In general I would avoid using dicts in django templates because they are awkward.

Aaron
  • 3,249
  • 4
  • 35
  • 51