December 8, 2010

Check object's parameter value in django template

I'm just finishing probably the most complexed project I'll ever build in django, at least by myself. During the development I've encountered numerous problems, some of without satisfying solutions on the web. So now for the next few posts I will share the results of my research, thinking and developing. Topic for today is :

How to check value of object's parameters in a template ?

Why do I ever need to do this kind of thing you may think. Yeah that's what I thought till now. But just think of my exact example - We have a site with some objects, that people can vote on. If someone has already voted we show him the result - if not, we render a voting button. Things are easy when rendering static page that is refreshed after each vote. But what if we need (just as I did) it to be dynamic ? I'm pretty sure that this problem can be solved using custom templatetag. But I've thought about a simpler solution using filters. So let's start.
I have created a context processor storing IP address of user. In my template I'm returning list of objects in a for loop, and on each object I'm using my filter, with IP as parameter:

{{ submission|check_voting:IP_ADDRESS|safe }}

And now the filter part :

@register.filter
def check_voting(obj, ip):
    result = obj.check_vote(ip)
    if result:
        result = "
%s votes
" % obj.votes else: result = "" % (settings.SITE_URL, obj.get_absolute_url() ) return result

As you can see my filter takes two arguments - object on which it was called, and ip. Then I'm doing some processing on my object's method 'check_vote' that returns me boolean value depending on query result for vote by ip. According to it's value I'm either showing a facebook like button used for voting, or just plain vote counter.
Hope you'll find this useful.

2 comments:

  1. Nice example, I would however change the naming of the function and variable. Functions which start with 'check' and variables named 'result' don't really show what they stand for.
    I would go for something like "has_voted = obj.has_voted(ip)"

    ReplyDelete
  2. good point. Here I've simplified things a bit. model's check_vote method basing on sent arguments performs different operations. Still not a bad idea to name the filter differently. Thanks.

    ReplyDelete