Replacing Django's Template Language With Jinja2
In this example we're going to take a closer look at the flexibility of Django's loose coupling philosophy by replacing its default templating language with Jinja2. Jinja2 is a very similar template language to the one provided by Django, but provides additional functionality like more flexible if syntax in templates, the option to raise an error when an undefined object is operated upon within templates (as opposed to Django's templating language which will always fail silently), and more flexible solutions for retrieving templates.
Lets get started.
First we need to download and install Jinja2.
sudo easy_install jinja2
Then make sure it works.
import jinja2
Create a Django project and app.
django_admin.py startproject loose_coupling cd loose_coupling python manage.py startapp with_jinja
Create a templates folder for your project, and one for the new app as well.
mkdir templates mkdir with_jinja/templates mkdir with_jinja/templates/with_jinja
Open up
loose_coupling/settings.py
and change the settings forINSTALLED_APPS
andTEMPLATE_DIRS
.INSTALLED_APPS = ( 'loose_coupling.with_jinja', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', ) import os ROOT_PATH = os.path.dirname(__file__) TEMPLATE_DIRS = ( os.path.join(ROOT_PATH,'templates'), os.path.join(ROOT_PATH,'with_jinja/templates'), )
Open up
loose_coupling/urls.py
and change its contents to this:from django.conf.urls.defaults import * urlpatterns = patterns( 'loose_coupling', (r'^$','with_jinja.views.index'), )
Now we just need to create our views. First, open up
with_jinja/views.py
and add these imports:import math,random from django.http import HttpResponse from django.conf import settings from jinja2 import FileSystemLoader, Environment
And then we're going to write a little convenience method to handle rendering via Jinja2.
template_dirs = getattr(settings,'TEMPLATE_DIRS') default_mimetype = gettattr(settings, 'DEFAULT_CONTENT_TYPE') env = Environment(loader=FileSystemLoader(template_dirs))
def render_to_response(filename, context={},mimetype=default_mimetype): template = env.get_template(filename) rendered = template.render(**context) return HttpResponse(rendered,mimetype=mimetype)
And next, lets create a simple custom test that our Jinja template is going to use to help render its output.
def greater_than_fifty(x): return x > 50 env.tests['gtf'] = greater_than_fifty
Now lets create the
index
view that we'll be using.def index(request): n = int(math.floor(100 * random.random())) return render_to_response('with_jinja/index.html',{'n':n})
As you can see, its a very simple view, merely passing a generated number to the
render_to_response
function we created before.Next, we need to create our
index.html
template that theindex
view is trying to render. To do that, first we are going to create abase.html
template in theloose_coupling/templates
directory. So, open uploose_coupling/templates/base.html
and add this to it<html> <head> <title> Loosely Coupled Django </title> </head> <body> {% block content %} {% endblock %} </body> </html>
And now we need to create the
loose_coupling/with_jinja/templates/with_jinja/index.html
template. It will extend our base template and be quite simple:{% extends 'base.html' %} {% block content %} <p> The number generated was { { n }}. </p> {% if n is gtf %} <p> The number was definitely greater than fifty.</p> {% else %} <p> Unfortunately, the number was below fifty.</p> {% endif %} {% endblock %}
Now, save all the files and run the project.
python manage.py runserver
Now navigate over to http://127.0.0.1:8000 and you'll see Django development server merrily rendering our Jinja2 template.
(You can download a zip of the project we developed here.)
Thanks to Django's loose coupling philosophy, it was really quite painless to switch over to using Jinja2 instead of the default templating language. As this series continues we'll look at how this isn't just a freak occurance, but occurs throughout the Django stack.