[Django]-How to use jinja2 as a templating engine in Django 1.8

27👍

Frist you have to install jinja2:

$ pip install Jinja2

Then modify your TEMPLATES list in the settings.py to contain the jinja2 BACKEND :

TEMPLATES = [

    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [os.path.join(BASE_DIR, 'templates/jinja2')],
        'APP_DIRS': True,
        'OPTIONS': {'environment': 'myproject.jinja2.Environment',}, 
    },
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
           ],
        },
    },
]

where templates/jinja2 is the directory with your jinja2 template files.

And in your views.py file:

from __future__ import absolute_import  # Python 2 only
from jinja2 import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse

def environment(**options):
    env = Environment(**options)
    env.globals.update({
       'static': staticfiles_storage.url,
       'url': reverse,
    })
    return env

This makes static and url available in your Jinja2 templates.

P.S. For more details see this article.

👤doru

16👍

Took me quite some time to figure out everything, answers here weren’t all that helpful.

doru’s answer is closest to truth but is incomplete.

How to use jinja as templating language:

1.Create jinja2.py file in your project folder. This is required to modify the default jinja2 Environment (in our case, passing some additional global variables).

location: {root}/main/jinja2.py:

from __future__ import absolute_import  # Python 2 only
from jinja2 import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.urlresolvers import reverse

def environment(**options):
    env = Environment(**options)
    env.globals.update({
       'static': staticfiles_storage.url,
       'url': reverse,
    })
    return env

2.Add jinja2 backend to django project settings file, including our modified environment.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'environment': "main.jinja2.environment",
        },
    },
    ...
]

3.Now you no longer need to import jinja2 anywhere, in your views, you will be using jinja templates through django just like django templates:

from django.shortcuts import render

def index(request, **kwargs):
    return render(request, "index.html.j2", {'title': 'MyTitle', 'text': "MyText"})

And finally, with APP_DIRS set to True jinja will search templates in all installed apps jinja2 directories. (unlike DTL that searches for templates folder). If you want to change that behavior, or want some extra tweaking, like extension match, filtering or global variables, you should look at django-jinja extension.

You may also provide additional directories to search for templates via TEMPLATES['DIRS'] option of settings.

👤IvanX

2👍

Mixed Django and Jinja2 Template: Environment: Django 1.8 + Jinja2.

I have some legacy Django templates and it’s not so easy to rewrite them all at once to Jinja2, so add this custom {% jinja_include "some_template.jinja" %} tag to my_custom_tags.py:

from django.template.loader import get_template
from django import template
register = template.Library()

@register.simple_tag(takes_context=True)
def jinja_include(context, filename):
    template = get_template(filename)
    return template.render(context.flatten())

Call it like this from your Django template:

{% load my_custom_tags %}
{% jinja_include "some_template.jinja" %}

2👍

Update for Django 3+: Real Life config Jinja2 3.0.X +

<project_name>/settings.py

TEMPLATES = [
{
    "BACKEND": "django.template.backends.jinja2.Jinja2",
    "DIRS": [os.path.join(BASE_DIR, "ui", "templates")], # You can add a subdirectory like /jinja2 if you don't want Jinja2 to be default. But for consistency I do not recommand
    "APP_DIRS": True,
    "OPTIONS": {
        'environment': ".".join([os.path.basename(BASE_DIR), 'jinja2.environment']),
        "context_processors": [
            "django.contrib.auth.context_processors.auth",
            "django.template.context_processors.debug",
            "django.template.context_processors.i18n",
            "django.template.context_processors.media",
            "django.template.context_processors.static",
            "django.template.context_processors.tz",
            "django.contrib.messages.context_processors.messages",
        ],
    }
},
{
    "BACKEND": "django.template.backends.django.DjangoTemplates",
    "DIRS": [],
    "APP_DIRS": True,
    "OPTIONS": {
        "context_processors": [
            "django.template.context_processors.debug",
            "django.template.context_processors.request",
            "django.contrib.auth.context_processors.auth",
            "django.contrib.messages.context_processors.messages",
        ],
    },
},]

<project_name>/<project_name>/jinja2.py

import inspect
import logging

from django.contrib import messages
from jinja2 import Environment, pass_context
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse

import ui.templatetags.extras as extras_filters
from crispy_forms.utils import render_crispy_form

logger = logging.getLogger(__name__)

# /!\ This this how you make csrf token generated by crispy properly injected
@pass_context 
def crispy(context, form):
    return render_crispy_form(form, context=context)

def environment(**options):
    logger.debug("Jinja2 environment loading")
    env = Environment(**options)
    env.globals.update({
       "get_messages": messages.get_messages,
       "static": staticfiles_storage.url,
       "crispy": crispy,  # this line is different
       "url": reverse,
   })
   # Bonus, get your django custom templatetag, backward compatible with Django Template
   env.filters.update(dict(inspect.getmembers(extras_filters, inspect.isfunction)))
   return env

/ui/views.py

import logging

from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit


logger = logging.getLogger(__name__)

class AddRemoteServerForm(forms.Form):
    name = forms.CharField(max_length=20, min_length=3)
    url = forms.CharField(max_length=200)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
        'name',
        'url',
        Submit('submit', 'Associate Server')
    )

<project_name>/ui/views.py

def add_remote_server(request):
if request.method == 'POST':
    form = AddRemoteServerForm(request.POST)
    logger.debug(form.data.dict())
    logger.debug("Form valid ? %s " % form.is_valid())
    if form.is_valid():
        d = form.data.dict()
        # TODO: Implmenent your business logic
        return redirect('/remote_servers/')
else:
    form = AddRemoteServerForm()
context = {'form': form}
return render(request, 'form.html', context)

<project_name>/ui/templates/form.html

{% extends "base.html" %}
{% block extraappendjavascript %}
{% endblock %}
{% block content %}
<div class="container">
    <div class="card">
        <div class="card-body">
            {{ crispy(form) }}
        </div>

    </div>
</div>
{% endblock %}

<project_name>/ui/templatetags/extras.py # Bonus, FYI

import logging
import os
from datetime import datetime, timedelta

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()

logger = logging.getLogger(__name__)
@register.filter(is_safe=True)
def js(obj):
    try:
        return mark_safe(json.dumps(obj))
    except Exception:
        return "{}"

0👍

From the Django website (please look at this for further guidance) in settings.py:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            # ... some options here ...
        },
    },
]

BACKEND is a dotted Python path to a template engine class implementing Django’s template backend API. The built-in backends are django.template.backends.django.DjangoTemplates and django.template.backends.jinja2.Jinja2.

Basically find out where in your settings.py file there is a TEMPLATES variable and set the backend (or make sure the backend) resembles the one above (as Jinga is built-in). If all fails, replace the django.template.backends... with django.template.backends.jinja2.Jinja2 (though I don’t think that is necessary).

Leave a comment