29

Mar

Filed in Code, Django, How-To's, Python |

Every time I meet someone new who asks me about Django, I tell them exactly what I think. It’s a great product. It does exactly what it’s designed to do. Allows you to build decently structured applications rapidly, without much overhead in doing so. One of the other things I tell them, is that the first they should do is scrap the template engine, and install Jinja.

Jinja is a sandboxed template engine, written in Python of course. It’s created by the guys over at Pocoo. It has a number of improvements over the Django engine, including faster rendering. Most of all, it allows you to place logic in templates where you need to, when Django does not.

Core Differences

Jinja templates are not 100% compatible with Django, and vice versa. Some of the biggest changes include methods required parenthesis, being able to access and pass attributes marked as pseudo-private (e.g. instance._meta), and a number of additional types of calls in templates. You will also find that all keywords are lowercase, those being true, false, none, and undefined. Best of all, you can use else if and any operator inside your if clauses just like you can in Python. No more clustered lists of {% if %}{% if %}{% ifnotequal %}.

Jinja

{% extends "bone/bone.html" %}

{% block content %}
<h1>My Objects</h1>
{% for object in my_objects.iteritems() %}
    <li class="{% cycle 'row1','row2','row3','row4' %}"><a href="{{ object.get_absolute_url }}">{{ object.name|escape }}</a><br /></li>{% endfor %}
{% endblock %}

Django

{% extends "bone/bone.html" %}

{% block content %}
<h1>My Objects</h1>
<ul>
{% for object in my_objects.iteritems %}
    <li class="{% cycle row1 row2 %}"><a href="{{ object.get_absolute_url }}">{{ object.name|escape }}</a><br /></li>
{% endfor %}
{% endblock %}

As you can see from the example above, the code is almost identical. Again, the main difference being how you access methods. You’ll also notice the cycle example I included, which can take any number of arguments, but you must also pass variables. Jinja doesn’t assume everything is a string as Django does.

Update: It seems Django (since a few months) supports multiple strings in the cycle like Jinja. Django also now supports auto-escaping, so the |escape would be invalid in the Django example (unless you did {% autoescape off %}).

Filters and Template Tags

One of my favorite features in Jinja are the filters and template tags. It provides a lot of useful filters, such as capture and filters are also much more flexible than they are in Django. Jinja filters and template tags are also all loaded into memory initially. There is no need to use {% load library %}. You can also set variables within your template if you want to optimize things, with {% set varname = value %}.

Another feature with you’ll find in Jinja are tests. Tests are simply that, a test on an element. Some common tests include even, odd, and sameas. Tests are used in the form of varname is test [optional arguments]. These can be used both within if statements, and variable calls.

Installing Jinja

Jinja has been made pretty easy to install with Django. While this might change (a bit) if I have my way, it still works fairly well with a little bit of magic. So to begin the install, you first need to the grab the package. I recommend getting trunk, via setuptools, using easy_install Jinja==dev. Once you’ve installed Jinja, you’re going to want to include a few lines at the bottom of settings.py.

# Initialize django.contrib.jinja
from jinja.contrib import djangosupport
djangosupport.configure()

These lines perform a little magic in the backend. They allow you to import Jinja from django.contrib.jinja, and include some conversion tools for Django template filters.

To use Jinja within your page, you then need to from django.contrib.jinja import render_to_response, render_to_string. I haven’t used Django’s template engine in almost two years, so the syntax may not match, so here’s an example:

def myview(request):
    return render_to_response('mytemplate.html', request=request)
 
def myotherview(request):
    context = {'myvar': True}
    return render_to_response('mytemplate.html', context, request)

The request and context variables are completely optionally. If you pass request it will cause your context processors to render.

Converting Django Filters

Due to Jinja not implementing nearly as many defaults (most are edge cases, this is a design decision), converting Django filters is stupidly simple in Jinja. You first need to import the conversion function, and the registration function:

from django.contrib.jinja import register, convert_django_filter

Once our functions are available, the rest is easy:

# Import the filter we want to convert
from django.template.defaultfilters import floatformat

# Register the converted filter.
register.filter(convert_django_filter(floatformat), 'floatformat')

Simple, right? Now you just need to make sure this file gets imported somehow on initialization. The easiest way is to create a utilities app, or something similar, and load them there. E.g. myproject.template.filters. You’ll then need to place this inside of your INSTALLED_APPS setting.

Wrap Us

If you’re not convinced yet, or you want to learn more, head over to the Jinja website and read the documentation.

View Comments Responses to "Using Jinja With Django"

Subscribe to this topic with RSS or get the Trackback URL
Alexander Solovyov (Mar 30th):

> Best of all, you can use else if and any operator inside your if clauses just like you can in Python. No more clustered lists of {% if %}{% if %}{% ifnotequal %}.

You can use custom template tag like pyif in Django:

http://www.djangosnippets.org/snippets/130/

> One of my favorite features in Jinja are the filters and template tags.

I see no docs about template tags in Jinja on their site.

> filters are also much more flexible than they are in Django

Please, can you give example?

> Jinja filters and template tags are also all loaded into memory initially.

Django’s too.

> Another feature with you’ll find in Jinja are tests.

Hm. But filters are the same, isn’t it?

Baczek (Mar 30th):

I write test filters so their name starts with ‘is_’, e.g.:

{% if user|is_registered_for:event %} … {% endif %}

works well and is quite readable.

David (Mar 30th):

Baczek, in Jina that could be written as if `user is registered_for event` or `user|is_registered_for(event)`

Nick (Mar 30th):

Hmmm, I really don’t see any reasons for me to switch to Jinja. I really like the idea to not write python code in template language. Designer doesn’t need to know python. And there is less possibility to hack site via template editing.
Converting filters (on-the-fly I think?) doesn’t seem a good idea too and kills performance.

David (Mar 30th):

It converts them when the file is initialized, it doesnt do it over and over.

And if you’re at risk of your template editors hacking your site, then they shouldn’t be editing templates..

Ned (Mar 30th):

If Jinja doesn’t do autoescaping, then be very careful. Django’s autoescaping is the best thing they’ve done to improve the security of Django sites in a long time. It prevents human error from creating XSS holes.

Nick (Mar 30th):

David, I mean that risk of injecting harmful python code into templates is bigger than not to allow python code in templates directly.

And again, I don’t see any valuable (for me of course) reasons to switch to Jinja. So all others reasons are more subjective than objective.

David (Mar 30th):

Django isn’t that much safer than Jinja. Both are fully sandboxed, Jinja just allows you to do more in it than Django, without extra hassle with template tag creation etc..

Greg (Mar 30th):

I don’t see much reason to consider replacing Django’s tightly integrated template system with an external, un-official one. The reasons listed in this article are vague and lack any backing.

I’m not trying to flame here, but I really don’t see what Jinja can do for me that Django can’t. I don’t think you should ever have Python code or extensive logic in template files, either.

Again, no flame intended, but one has to be really careful when telling new (or old) Django developers that something is better when there isn’t much here to substantiate that notion.

Justin (Mar 30th):

There are a couple of great Jinja features that David left out.

First is macros, with support for recursion. Writing template code for producing trees is difficult, making it tempting to produce markup in a view or templatetag. That’s a pretty glaring omission on Django’s part, IMO. Jinja’s loops support recursions too.

The second is that with a normal parenthesized parameter syntax, you can pass more than one argument to a filter or method. This is absolutely necessary for for some kinds of filters which in Django have to parse an argument string. The filter syntax is nice looking, but without parentheses it’s very limited to a strict left-to-write precedence rule. This also encourages more view logic and templatetags.

Cassie (May 17th):

hi David I was wondering if you were the David Cramer from Illinois that is in CYT. DOn’t think I’m stalking you I am from CYT and I was wondering if I googled names from CYT they would come up. Just wondering.

Robert Thomson (rmt) (Dec 11th):

I managed to get Django generics to play nicely with Jinja2. Here's my code: http://www.djangosnippets.org/snippets/1241/ … now, I wonder how hard it would be to make an {% extendsjinja %} tag for Django templates (or the ability to have Django recognise a particular template as Jinja, and just play nicely) … that would make integration of third party apps a breeze.. I'll leave that one for when I'm reaaaally bored though. :-)

neil (May 21st):

i never comment on articles but for some reason feel like doing it, so here we go…

while probably sufficient for most web development, the django template language lacks the standard functionality desired for an application, mainly a complete set of conditionals and operations and the ability to easily pass arguments to function calls.

this is necessary because templates house the app rendering content, and need to make decisions about what to show the user by examining and processing the context that is passed.

this gets very messy and laborious without complete logic, operations and function calls – you end up writing a lot of functions to create strings the templater is too awkward to produce and having to pre-compute series of flags in views to add to the context for operations that are a pain to do in the template. this causes problems when multiple views render the same template – you end up with a ‘respond’ layer in-between that processes the context and generates the strings and flags the template needs – added complexity and dependency with little or no added value.

again, these issues are probably minor or negligible for most django web projects, but they become debilitating for applications (our typical small app is 100-200 source files).

i’m just checking out jinja, but after one app on the django template engine, i realized it wasn’t a viable solution for an application scale project.

oh, and it’s slow as all hell.

Stephen (Aug 3rd):

This article: http://lucumr.pocoo.org/2008/9/16/why-jinja-is-not-django-and-why-django-should-have-a-look-at-it makes a very persuasive technical argument why the Django template system is deficient and why the Django people should at least take a look at Jinja.

I have written piles of Django template tags for my own site, including a recursive control structure, a “bind” tag to do the same thing as the Jinja “set” tag, and many others… these are utility things really lacking in Django, and I have to say the more I work with Django the more it feels like a real lack.

A couple patterns are really common when writing template tag libraries for apps. One is a tag which calls a function and branches based on the result, e.g., to test user privileges. I rewrote this tag so many times that I developed a generic function caller control structure. Probably the biggest one, though, is writing tags that do a database lookup and bind a data structure to a variable for off-side content that isn’t related necessarily to the main content of the page and therefore inconvenient to handle in every view.

This is a bloody massive amount of overhead for what turns out to be an extremely common task. In Jinja, though, you can bind axctual functions to the context and by using the set tag and calling the function retrieve and this kind of information in the template. With Django integration, you could use context processors to place the necessary functions in all contexts and presto, vastly less boilerplate to achieve this common and simple objective.

I mostly really like Django and even the Django templates, but I’m thinking twice right now.

[...] Update: I just had a look at Jinja templates and it looks like they offer some interesting tools on top of Django templates, like simple expressions (e.g. {{2+2}}) inside the template tags. The only way to do some of the stuff that Jinja does out of the box with Django is by writing your own template tag. There is a nice post on why you should use Jinja, even with Django here. [...]

bedava film izle (Dec 21st):

It converts them when the file is initialized, it doesnt do it over and over.

And if you’re at risk of your template editors hacking your site, then they shouldn’t be editing templates..

air jordan 10 (Jun 5th):

Well , the view of the passage is totally correct ,your details is really reasonable and you guy give us valuable informative post, I totally agree the standpoint of upstairs. I often surfing on this forum when I m free and I find there are so much good information we can learn in this forum! http://spoon8.net/

Leave A Reply

 Username (*required)

 Email Address (*private)

 Website (*optional)

Note: Comments moderation may be active so there is no need to resubmit your comment.
blog comments powered by Disqus