key and value of dictionary in html file Django [duplicate] - python

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"

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.

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.

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.

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

django_template_filter
filter name get_value_from_dict
{{ your_dict|get_value_from_dict:your_key }}

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.

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.

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

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.

Related

Accessing dictionaries given django template's attributes?

So my problem is that I need to iterate over a dictionary given an attribute, which is the value of the for loop. For example, I have a dictionary called my_dictionary which is being iterated by a for loop in a django template, with an attribute called q. What I need is to access to that dictionary by using the q attribute. I tried with {{my_dictionary.q}}, {{my_dictionary.{{q}} }} but none of them did work. What can I do? I guess it should be similar as in Python my_dictionary[q]. Thank you.
Update: Actually, q has nothing to do with my_dictionary. Suppose that q is every element of a list [1,2,3] meanwhile my_dictionary is a dictionary with the following form: {1: ['a','b','c'], 2:['a'], 3:['c']}. So what I'm trying to do is access to each value of the dictionary given the values of the first list [1,2,3].
Suppose you return a dictionary from view to a template. Say your dictionary name is my_dictionary then in a template you need to do like this:
{% for q in my_dictionary %}
<p> {{ q.your_dictionary_key_name }} </p>
{% endfor %}
for iterating over list items in a dictionary
{% for key, value in dictionary.items %}
<li>{{value}}</li>
{% endfor %}
You could write a custom template filter:
from django.template.defaulttags import register
register = Library()
...
#register.filter
def get_item(dictionary, key):
# use .get so that if the key does not exist a KeyError will be raised
return dictionary.get(key)
usage in templates:
{% for q, value in my_dictionary.items %}
{{ my_dictionary.items|get_item:<key_variable_here> }}
{% endfor %}

Django template language unpacking a dict

I have a dictionary passed (as part of another object) to the django template language.
The object, called 'poll' has attributes self.text and self.votes, where the former is a string, and the latter is a dict.
The dict, looks like this:
{'a1': 45.92422502870264, 'a2': 53.50172215843857}
I am trying to list each label, with its accompanying number, using the following:
{% for l, x in poll.votes %}
<p>{{ l }} {{ x }}</p>
{% endfor %}
Django responds with
Exception Type: ValueError
Exception Value: Need 2 values to unpack in for loop; got 3.
I tried .iteritems - The docs explain that .iteritems is not the correct way to do this, but they don't explain what the correct way is.
You just iterate the same way you would in python, but in Djangos templating language (DTL) syntax
{% for key, value in dictionary.items %}
Your poll.votes is a dict but you're not iterating the items but the keys in your code.
You can find an overview of jinja here. Its worth noting that jinja isn't what django uses but its handy for a condensed reference since many things are the same (jinja is based upon DTL) instead of digging through djangos docs.
For Djangos tempaltes heres the documentation reference
you too can do this:
{% for variable in poll %}
{{ variable.name }} - {{ variable.votes }}
{% endfor %}

Django Template: Access list element by model attribute

I have a list of model instances and want to calculate a value for each of it in my view to show it on the page.
I got stuck when I tried to pass this value to the template.
My attempts:
1) Something like {{ list.(model.pk) }} - obviously a syntax error. I searched around the web and the documentation but couldn't find a valid syntax to evaluate a specific part of a "dot"-concatenation first.
2) Give the model a non-database attribute and access it simply with {{ instance.non_db_value }}. But it seems that the template gets its model values directly from the database, so this also failed.
A somewhat ugly solution might be to wrap all the model instances in the model list into a list of single lists, two values each: the first the instance itself, the second the calculated value I need to pass to the template.
With this, I could access the values with something like this:
{% for entry in wrapperlist %}
{{ wrapperlist.entry.0 }} <-> {{ wrapperlist.entry.1 }}
{% endfor %}
But I don't think this can't be it - am I thinking in the wrong direction? Any suggestions or ideas?
First of all, template doesn't get model values directly from DB. For template processor, your model instance it is yet another object. So, it is totally ok to:
#views.py
foo_list = models.Foo.objects.all()
for foo in foo_list:
foo.non_db_property = some_method()
render_to_response('template.html', {'foo_list': foo_list})
and in template:
{% for foo in foo_list %}
<li>{{ foo.non_db_property }}</li>
{% endfor %}
if it doesn't work for you, check out for errors.
Another approach is to create a model method if value is based on model properties only:
#models.py
class Foo(models.Model):
bar = models.CharField(max_length=3)
....
def non_db_value(self):
#calculate
return value
template will remain the same as above

Django Templates: Is there a way to query a specific object based on its property (instead of iterating over all)?

Let's say I have an object 'users' coming in as a context, which I know contains many user objects. Now, in my template, I want to access a specific user which I know has a specific property value (let's say id of 10), and then display another property associated with that user. I know that I can do:
{% for user in users %}
{% if user.id == 10 %}
{{ user.age }}
{% endif %}
{% endfor %}
I know that I could extract that user in my view and pass just that one object (?) but in this case it makes sense to have all of them.
I feel that there ought to be an easier way to do this but I'm a Django/templating newbie. Tried searching but wasn't sure how to phrase it..
this is really a job for template tags
templatetags/my_tags.py
...
#register.filter
def where_id(users,user_id):
return filter(lambda u:u.pk==user_id,users)
...
sometemplate.html
{%load my_tags %}
...
{% for user in users|where_id:10 %}
....
If you are working with unique fields, it might be better to use get, rather than filter. Here's a generic way to do that, inspired by Joran's answer and this answer.
my_template.html:
{%load my_tags %}
...
This is the user with pk=1: {{ users|get:"pk, 1" }}
....
templatetags/my_tags.py:
from django.template import Library
from django.core.exceptions import ObjectDoesNotExist
register = Library()
#register.filter
def get(models, argstring):
args = argstring.split(',')
if len(args) != 2:
raise ValueError("Exactly two arguments required, separated by comma")
field, value = args
try:
return models.get(**{field: value})
except ObjectDoesNotExist:
return None

Can I access specific key values in dictionary from django template?

Is there any get() function for this instead?
{% for key, value in choices.items %}
<li>{{key}} - {{value}}</li>
{% endfor %}
From python I have the get() function to get values from a specific key. But I couldn't find a corresponding way to do that with django template tags. So I wonder is it possible?
I need to get specific values since using loops adds a lot of new lines in the html source.
Or should take care of the output inside the view before sending it out to the template, which method is better?
You can use {{ choices.items.key }} to access a specific dict element.
There is no reason to care about whitespace in the HTML code though; the typical end-user has no real business in reading it and if he's curious he an always use a DOM viewer or run it through a HTML beautifier.
If you want a specific value, just add it to the dotted-path:
{{ choices.items.somekey }}
will get you the value of choices.items['somekey'] if choices.items is a dict.
I think you are way advance now, just to share my point. you could do this way as well
{% for value in dict %}
{{value}}
{% endfor %}
or with key, value like
{% for key,value in dict.items %}
{{key}} : {{ value }}
{% endfor %}
If choices type is DICT like {}.
{{choices.somekey|default:""}}
If choices.items is DICT type.
{{choices.items.somekey|default:""}}
Try See little example.
# In Views.py
def dict_test(request):
my_little_dict = {"hi": "Hello"}
....
# in Template
{{my_little_dict.hi}}
You can specify as {{ choices.key_name }}
It worked for me. Just simple
{{ choices.values }}
This gives you a list of all the values in the dictionary at once.

Categories