Django templates and variable attributes - python

I'm using Google App Engine and Django templates.
I have a table that I want to display the objects look something like:
Object Result:
Items = [item1,item2]
Users = [{name='username',item1=3,item2=4},..]
The Django template is:
<table>
<tr align="center">
<th>user</th>
{% for item in result.items %}
<th>{{item}}</th>
{% endfor %}
</tr>
{% for user in result.users %}
<tr align="center">
<td>{{user.name}}</td>
{% for item in result.items %}
<td>{{ user.item }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Now the Django documention states that when it sees a . in variables
It tries several things to get the data, one of which is dictionary lookup which is exactly what I want but doesn't seem to happen...

I found a "nicer"/"better" solution for getting variables inside
Its not the nicest way, but it works.
You install a custom filter into django which gets the key of your dict as a parameter
To make it work in google app-engine you need to add a file to your main directory,
I called mine django_hack.py which contains this little piece of code
from google.appengine.ext import webapp
register = webapp.template.create_template_register()
def hash(h,key):
if key in h:
return h[key]
else:
return None
register.filter(hash)
Now that we have this file, all we need to do is tell the app-engine to use it...
we do that by adding this little line to your main file
webapp.template.register_template_library('django_hack')
and in your template view add this template instead of the usual code
{{ user|hash:item }}
And its should work perfectly =)

I'm assuming that the part the doesn't work is {{ user.item }}.
Django will be trying a dictionary lookup, but using the string "item" and not the value of the item loop variable. Django did the same thing when it resolved {{ user.name }} to the name attribute of the user object, rather than looking for a variable called name.
I think you will need to do some preprocessing of the data in your view before you render it in your template.

Or you can use the default django system which is used to resolve attributes in tempaltes like this :
from django.template import Variable, VariableDoesNotExist
#register.filter
def hash(object, attr):
pseudo_context = { 'object' : object }
try:
value = Variable('object.%s' % attr).resolve(pseudo_context)
except VariableDoesNotExist:
value = None
return value
That just works
in your template :
{{ user|hash:item }}

#Dave Webb (i haven't been rated high enough to comment yet)
The 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.e., foo["bar"])
* Attribute lookup (e.g., foo.bar)
* Method call (e.g., foo.bar())
* List-index lookup (e.g., foo[bar])
The system uses the first lookup type that works. It’s short-circuit logic.

As a replacement for k,v in user.items on Google App Engine using django templates where user = {'a':1, 'b', 2, 'c', 3}
{% for pair in user.items %}
{% for keyval in pair %} {{ keyval }}{% endfor %}<br>
{% endfor %}
a 1
b 2
c 3
pair = (key, value) for each dictionary item.

shouldn't this:
{{ user.item }}
be this?
{{ item }}
there is no user object in the context within that loop....?

Related

Displaying python list of dictionaries on front-end using django [duplicate]

I'm passing a dictionary from my view to a template. So {"key1":"value1","key2":"value2"} is passed in and looping through key,value pairs is fine, however I've not found an elegant solution from access directly in the view from a specific key, say "key1" for example bu json.items["key1"]. I could use some if/then statements, but I'd rather do directly is there a way?
Here is looping code in the html template:
{% for key, value in json.items %}
<li>{{key}} - {{value}}</li>
{% endfor %}
The Django template language supports looking up dictionary keys as follows:
{{ json.key1 }}
See the template docs on variables and lookups.
The template language does not provide a way to display json[key], where key is a variable. You can write a template filter to do this, as suggested in the answers to this Stack Overflow question.
As #Alasdair suggests, you can use a template filter.
In your templatetags directory, create the following file dict_key.py:
from django.template.defaultfilters import register
#register.filter(name='dict_key')
def dict_key(d, k):
'''Returns the given key from a dictionary.'''
return d[k]
Then, in your HTML, you can write:
{% for k in json.items %}
<li>{{ k }} - {{ json.items|dict_key:k }}</li>
{% endfor %}
For example, to send the below dictionary
dict = {'name':'myname','number':'mynumber'}
views :
return render(request, self.template_name, {'dict': dict})
To render the value in html template:
<p>{{ dict.name }}</p>
It prints 'myname'
To overcome this problem you could try something like this:
def get_context_data(self, **kwargs):
context['cart'] = []
cart = Cart()
cart.name = book.name
cart.author = book.author.name
cart.publisher = book.publisher.name
cart.price = 123
cart.discount = 12
cart.total = 100
context['cart'].append(cart)
return context
class Cart(object):
"""
Cart Template class
This is a magic class, having attributes
name, author, publisher, price, discount, total, image
You can add other attributes on the fly
"""
pass
By this way you can access your cart something like this:
{% for item in cart %}
<div class="jumbotron">
<div>
<img src="{{item.image}}" />
<div class="book_name"> <b>{{item.name}}</b></div>
<div class="book_by"><i>{{item.author}}</i></div>
<span>Rs. {{item.price}}</span> <i>{{item.discount}}% OFF </i>
<b>Rs. {{item.total}}</b>
{% endfor %}

Accessing session variable based on variable in for loop django template

I have some products listed which can be in a cart, this cart is stored in a session variable dictionary for which the key is the product id and the value is some information about the quantity and stuff. I want to add the option to view (on the products page) how many of that product are in your cart.
I know I can access session variables in a django template like this:
{{ request.session.cart.2323.quantity }}
Problem is, the key (2323 in this case) is a variable which depends on a for loop:
{% for prod in products %}
<p>{{ request.session.cart[prod.name].quantity }}</p>
{% endfor %}
But implementing it like that unfortunately is not possible. Is there any way in which this would be possible or would I have to change the way my cart works?
You should implement a custom template filter like this to have the ability to use getattr.
from django import template
register = template.Library()
#register.simple_tag
def get_object_property_dinamically(your_object, first_property, second_property):
return getattr(getattr(your_object, first_property), second_property)
{% load get_object_property_dinamically %}
{% for prod in products %}
<p>{% multiple_args_tag request.session.cart prod.name 'quantity' %}</p>
{% endfor %}

Django - create custom tag to acces variable by index in template

I have a HTML template in django. It get's two variables: list of categories (queryset, as it it returned by .objects.all() function on model in django) and dictionary of contestants. As a key of the dictionary, I'm using id of category, and value is list of contestats.
I want to print name of the category and then all the contestants. Now I have this:
{% for category in categories_list %}
<h1>category.category_name</h1>
{% for contestant in contestants_dict[category.id] %}
{{ contestant }} </br>
{% endfor %}
{% endfor %}
However, when I run it, I get error:
TemplateSyntaxError at /olympiada/contestants/
Could not parse the remainder: '[category.id]' from 'contestants_dict[category.id]'
What I know so far is that I can't use index in template. I thought that {% something %} contains pure Python, but it shoved up it's just a tag. I know that I have to create my own simple_tag, but I don't know how. I read the docs Writing custom template tags, but there is such a little information and I wasn't able to fiqure out how to create (and mainly use in a for loop) a tag, that will take dict, key and return the value. What I tried is:
templatetags/custom_tags.py:
from django import template
register = template.Library()
#register.simple_tag
def list_index(a, b):
return a[b]
and in template:
{% for contestant in list_index contestants_dict category.id %}
But I get TemplateSyntaxError.
Could you please explain/show me how to create the tag, or is there a better way to do this?
Thanks.
//EDIT:
I managed to do it this way:
{% list_index contestants_list category.id as cont %}
{% for contestant in cont %}
it works, but it takes 2 lines and I need to create another variable. Is there any way to do it without it?
If you don't want 2 lines like that you should be able to use a filter i think
#register.filter
def list_index(a, b):
return a[b]
Then the usage like this
{% for contestant in contestants_dict|list_index:category.id %}
{{ contestant }} </br>
{% endfor %}

Python/Django: Simple Django Template

Hi I am using App Engine/Python to do a simple website. I have some trouble with a Django template problem.
In short, I want to use a "ShortName" to access a "LongName".
The soource code:
LongName={"so":"stackoverflow","su":"superuser"}
ShortName=['so','su']
Then I pass these two parameters to the templates.
In the template I write:
{% for aname in ShortName %}
{{ aname }} stands for {{ LongName.aname }},
{% endfor %}
The output is:
so stands for, su stands for
No error is given. The LongName.aname wont work.
I have no idea whats wrong.
This is trying to access LongName['aname'], not LongName[aname].
You might have to write a custom template tag/filter to get this to work. This Django bug (marked WONTFIX) has a simple implementation:
def get(d, key):
return d.get(key, '')
register.filter(get)
which you would use by
{{ LongName|get:aname }}
after adding it to your app (that SO answer shows how to do it on GAE).
You could also pre-make a variable to loop over in the view, by passing in
# in view
name_abbrevs = [(k, LongName[k]) for k in ShortName]
# in template
{% for short_name, long_name in name_abbrevs %}
{{ short_name }} stands for {{ long_name }}
{% endif %}
If you really don't want to add a template tag -- which isn't that bad! you just make one file! :) -- or pass in an extra variable, Vic's approach will let you do this without touching the Python files at all. As he mentions, it involves a lot of pointless iteration, but it'll work fine for small lists.
Django templates have a drawback here. I've been in the same situation before. What you have to do is iterate over all the keys in LongName, and check if the key you're looking for matches the ShortName. Here you go:
{% for aname in ShortName %}
{% for short_version, long_version in LongName %}
{% if aname == short_version %}
{{ aname }} stands for {{ long_version }},
{% endif %}
{% endfor %}
{% endfor%}
It's inefficient, and essentially a pointless O(n^2) mechanism. However, there's no better way in pure Django templates to refer to entries of a dict by a variable name.

how to run this code in django template

this is my code :
{% for i,j in enumerate(a) %}
{{i}} ,{{j}}
{% endfor%}
but , it show a error , i think it cant run the enumerate method ,
so how to run the enumerate in django template ,
thanks
The template subsystem has some special constructs built into the for/endfor block that allows you to access the current index of the loop without having to call enumerate.
{% for j in a %}
{{ forloop.counter0 }}, {{ j }}
{% endfor %}
While this snippet solves your immediate problem, if you're expecting to have access to Python builtins and other Python constructs inside your Django templates, you may be misunderstanding the sandbox that it provides/enforces.
you can use {{ forloop.counter }} or {{ forloop.counter0 }} for the same effect, the latter is 0-indexed, thus more like enumerate.
{% for item in a %}
{{ forloop.counter }}, {{ item }}
{% endfor %}
Link related
Django template makes up the presentation layer and are not meant for logic. From the docs
If you have a background in programming, or if you’re used to languages which mix programming code directly into HTML, you’ll want to bear in mind that the Django template system is not simply Python embedded into HTML. This is by design: the template system is meant to express presentation, not program logic.
Now to get the same functionality in Django, you will have to complete your logic in the views.
views.py
def my_view(request, ...):
....
enumerated_a = enumerate(a);
....
return render_to_response('my_template.html', {'enumerated_a ': enumerated_a }..)
Now enumerate function returns an enumerate object which is iterable.
my_template.html
{% for index, item in enumerated_a %}
{{ index }},{{ item }}
{% endfor %}
Although I think you can probably change it to an enumerated list and use it like that as well.
If however you need to use a function within a template, i suggest you create a filter or a tag instead. For reference, check out http://docs.djangoproject.com/en/1.2/howto/custom-template-tags/

Categories

Resources