26

I have been looking on how to use jinja2 in django 1.8, but there is no complete source for using django with jinja2. I was wondering if you guys knew the process for using jinja2 in django. I have looked through the the official documentation and I have looked at the following question: How to setup django 1.8 to use jinja2?

but none of them clearly explain how to use jinja2 in an put-togther manner. I just started using django and don't know all the lingo in the docs. I would really appreciate the help.

Community
  • 1
  • 1
biiiju
  • 293
  • 1
  • 4
  • 5

5 Answers5

26

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.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
doru
  • 9,022
  • 2
  • 33
  • 43
  • 2
    And how can we add context_processors ? – ratata Jun 09 '16 at 10:14
  • 1
    Using context processors with Jinja2 templates is discouraged according to https://docs.djangoproject.com/en/1.11/topics/templates/#module-django.template.backends.django – Denis Trofimov Nov 08 '18 at 18:00
  • 1
    `APP_DIRS` for jinja2 has no effect. – Eric Mar 04 '20 at 10:16
  • 1
    In the settings, you configure environment as `myproject.jinja2.Environment`, but you should rather use `myproject.jinja2.environment` (**lowercase 'e'**) instead. The former loads the built-in Environment class, which does NOT contain your custom functions 'static' and 'url'. – Marcin Wojnarski Mar 11 '20 at 12:17
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
  • 340
  • 2
  • 8
  • 3
    ❝Django 2.0 removes the django.core.urlresolvers module, which was moved to django.urls in version 1.10. You should change any import to use django.urls instead.❞ See https://stackoverflow.com/a/43139407 – dmmfll Jul 28 '18 at 13:56
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" %}
fragilewindows
  • 1,394
  • 1
  • 15
  • 26
Kostyantyn
  • 5,041
  • 3
  • 34
  • 30
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 "{}"
MaxBlax360
  • 1,070
  • 1
  • 12
  • 15
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).

nonamorando
  • 1,556
  • 2
  • 14
  • 33
  • django template language is a django template api ? – shuboy2014 Nov 22 '16 at 07:23
  • @wkcamp the question IS in setting 'BACKEND': 'django.template.backends.jinja2.Jinja2'. Your reply is misleading. – Denis Trofimov Nov 08 '18 at 18:15
  • @DenisTrofimov I wrote this answer three years ago. My reply should first be considered outdated and irrelevant, given the date in which it was posted and the lack of votes it received. If you ignore that, then yes, it does not answer the question. – nonamorando Nov 09 '18 at 20:29