29
Mar
Using Jinja With Django
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.

11 Responses to "Using Jinja With Django"
> 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?
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.
Baczek, in Jina that could be written as if `user is registered_for event` or `user|is_registered_for(event)`
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.
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..
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.
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.
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..
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.
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.
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.
Leave A Reply