Replacing Django's Template Language With Jinja2

07/22/2008

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.

  1. First we need to download and install Jinja2.

    sudo easy_install jinja2
    
  2. Then make sure it works.

    import jinja2
    
  3. Create a Django project and app.

    django_admin.py startproject loose_coupling
    cd loose_coupling
    python manage.py startapp with_jinja
    
  4. 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
    
  5. Open up loose_coupling/settings.py and change the settings for INSTALLED_APPS and TEMPLATE_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'),
    )
    
  6. 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'),
    )
    
  7. 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.

  8. Next, we need to create our index.html template that the index view is trying to render. To do that, first we are going to create a base.html template in the loose_coupling/templates directory. So, open up loose_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 %}
    
  9. Now, save all the files and run the project.

    python manage.py runserver
    
  10. 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.

All Rights Reserved, Will Larson 2007 - 2014.