Jinja templates in Django

For more information:

Where to put Jinja template files

As we know, the default Django template engine looks for template files in each Django app in the templates subdirectory.

Similarly, the Jinja template engine looks in each Django app in the jinja2 subdirectory. (Unless you set APP_DIRS=False, but why confuse yourself?)

To help myself keep things straight, I use the convention that my Jinja template files end in .j2.html, but that’s not necessary; you can name your template files anything you want. It’s the directory you put them in that really matters.

Context

From https://docs.djangoproject.com/en/5.1/topics/templates/#django.template.backends.jinja2.Jinja2: “The most important entry in OPTIONS is ‘environment’. It’s a dotted Python path to a callable returning a Jinja2 environment. It defaults to ‘jinja2.Environment’. Django invokes that callable and passes other options as keyword arguments.”

See also

To set things in the context for all Jinja templates in Django, create a function that returns a jinja2.Environment, and set environment to its path in the Jinja Django template settings. For example:

# appname/jinja.py

from django.templatetags.static import static

def environment(**options):
    options.setdefault("autoescape", True)
    env = Environment(**options)
    env.globals.update(
        {
            "static": static,
              ...
        }
    )
    env.filters["my_format_date"] = my_format_date
    return env

and in settings.py:

TEMPLATES = [
    {
        "NAME": "django", ...
    },
    {
        "NAME": "jinja2", ...
        "OPTIONS": {
            "environment": "appname.jinja.environment",
        },
    },
]

Calling functions from Jinja templates

It’s very handy to be able to call code from your template and have the return value inserted into the output. With Django’s default template engine, you have to write template tags, though with the provided shortcut decorators it’s pretty easy.

With Jinja in Django, it’s also easy, just slightly different. Write a function that takes whatever args you like and returns a string:

from django.urls import reverse

def django_url_tag(urlname, *args):
    return reverse(urlname, args=args)

Add a reference to the function to the globals in the environment:

# appname/jinja.py


def environment(**options):
    env = Environment(**options)
    env.globals.update(
        {
            "url": django_url_tag,
            ...
        }
    )
    return env

In your templates, put calls to your function inside {{ }}:

# ...html
<a href="{{ url("home", 1, 2) }}">Home</a>

Filters

There’s not really a need for filters in Jinja, but you can create them if you want. It’s only the difference between writing:

{{ varname | filter(arg1, arg2) }}

and:

{{ function(varname, arg1, arg2) }}

If you prefer the former, write a function that takes the filter input as the first arg and any additional args after that, and returns a string:

def myfilterfunction(varname, arg1, arg2):
    return "somestring"

and add a reference to the Jinja environment by adding it to env.filters in your environment function:

env.filters["myfilter"] = myfilterfunction

Using Jinja templates from views

You don’t have to do anything different in your views to use Jinja templates. If Django finds the template file you ask for in the default Django template engine’s template directories, it’ll process it using the default Django template engine. If it finds the template file in the Jinja template engine’s template directories, it’ll process it using the Jinja template engine.

To help myself keep things straight, though, I use the convention that my Jinja template files end in .j2.html.

Example:

from django.shortcuts import render

def home(request):
  context = { ... }
  return render(request, "home.j2.html", context)

settings.py

See:

Update TEMPLATES:

TEMPLATES = [
    {
        "NAME": "django", ...
    },
    {
        "NAME": "jinja2",
        "BACKEND": "django.template.backends.jinja2.Jinja2",
        "DIRS": [BASE_DIR / "src" / "appname" / "jinja2"],
        "APP_DIRS": True,  # <app>/jinja2
        "OPTIONS": {
            "auto_reload": True,
            "environment": "appname.jinja.environment",
        },
    },
]