views:

227

answers:

3

Using Django templates in Google App Engine (on Python), is it possible to compare a template variable to an integer in an {% if %} block?

views.py:

class MyHandler(webapp.RequestHandler):
    def get(self):
        foo_list = db.GqlQuery(...)
        ...
        template_values['foos'] = foo_list
        template_values['foo_count'] = len(foo_list)
        handler.response.out.write(template.render(...))

My template:

{% if foo_count == 1 %}
     There is one foo.
{% endif %}

This blows up with 'if' statement improperly formatted.

What I was attempting to do in my template was build a simple if/elif/else tree to be grammatically correct to be able to state

#foo_count == 0:
There are no foos.

#foo_count == 1:
There is one foo.

#else:
There are {{ foos|length }} foos.

Browsing the Django template documents (this link provided in the GAE documentation appears to be for versions of Django far newer than what is supported on GAE), it appears as if I can only actually use boolean operators (if in fact boolean operators are supported in this older version of Django) with strings or other template variables.

Is it not possible to compare variables to integers or non-strings with Django templates?

I'm sure there is an easy way to workaround this - built up the message string on the Python side rather than within the template - but this seems like such a simple operation you ought to be able to handle in a template.

It sounds like I should be switching to a more advanced templating engine, but as I am new to Django (templates or any part of it), I'd just like some confirmation first.

+1  A: 

Django 1.2 allows for == operators in the {% if %} tag. If you need to compare two integers or other items, you can always use {% ifequal a b %}...{% endifequal %} in older versions of Django.

My guess is that you are reading the Development docs (django 1.2), but using django 1.1 or 1.1.1

However, if you need to do {{ foo|length }} and compare the output of that template tag + filter, you won't be able to. You'll need to fix your view logic to calculate that for you so you can use it in the template.

Also, depending on how you are using the list, you can look into for...empty:

http://docs.djangoproject.com/en/dev/ref/templates/builtins/#for-empty

xyld
is this the type of logic that would be deemed "too complicated" in any sort of Python templating engine, not just? Because this seems pretty simple to me - it's not as if I am attempting to execute actual code, just a few if statements.
matt b
if you are simply comparing two ints, its not complex, but older Django's (pre-1.2, which isnt formally released yet) need to use `{% ifequal %}`, try using ifequal and see if that works instead of `{% if 1 == 1 %}`
xyld
The current development version docs state "It is only possible to compare an argument to template variables or strings."
matt b
How you define "too complicated" depends on what you are using the templating language for. In other templating languages this logic is child's play - they give you a lot more expressiveness than Django templates. Anyway, if you do decide to go with another templating engine, consider [Mako](http://www.makotemplates.org) if you're comfortable with Python.
David Underhill
True, 'too complicated' is very subjective. The idea behind not letting you do things 'too complicated' was to avoid too much logic in templates. Not only is it a spot for error, but the initial intent of the templates was for web designers who may or may not have programming experience. Therefore, too much 'complexity' in templates could confuse them...
xyld
A: 

You're using a template variable named foo_list:

{% if foo_list == 1 %}

but there's no such variable in the template your code builds, only foo and foo_count.

Alex Martelli
AFAIK, undefined template vars are OK and just get ignored. Right? At the very least, its not a `syntax error`...
xyld
sorry, this was a typo caused by me trying to take real code and dumb it down - let me fix that.
matt b
+3  A: 

You are most probably using Django 0.96:

The App Engine Python environment includes three versions of Django: 0.96, 1.0.2, and 1.1. Django 0.96 is included with the App Engine SDK, and is the version that gets imported by default when an app imports the django package.

Source: http://code.google.com/appengine/docs/python/tools/libraries.html#Django

As xyld has said, you must use the ifequal templatetag, because boolean operators were included only in version 1.2, that is currently in beta.

The documentation for version 0.96 can be found here or you can also use version 1.1:

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

from google.appengine.dist import use_library
use_library('django', '1.1')

Of course, you can always download the entire Django project, and include it in your application's top level directory. Some tips on how to do that can be found in this article.

EDIT: Since the ifequal is not suited for integers, you can pass additional variables to your template.

class MyHandler(webapp.RequestHandler):
    def get(self):
        foo_list = db.GqlQuery(...)
        ...
        template_values['foos'] = foo_list
        template_values['foo_count'] = len(foo_list)
        template_values['one_foo'] = len(foo_list) == 1
        handler.response.out.write(template.render(...))

and in the template:

{% if one_foo %}
    You have one foo.
{% endif %}

or:

{% if foo_list %}
    You have {{ foo_count }} foo{{foo_count|pluralize}}.
{% else %}
    You have no foos
{% endif %}
jbochi
From the documentation of ifequal: "It is only possible to compare an argument to template variables or strings. ". Therefore it sounds unsuitable to be used for comparisons to an integer (to test the length of a list)
matt b
Sorry! I have edited my answer
jbochi