Jinja globals: Access data on all Jinja templates, like Django context processors

Just like Django templates offer context processors to facilitate the access of data on all Django templates, Jinja also offers its own version of the same feature which is called globals. Jinja in its out-of-the-box state has no globals, but in its Django integrated mode includes three globals to mimic Django's most common context processors, these globals are: request, csrf_input and csrf_token.

This means you get access to three Django context processor 'like variables in all Jinja templates used in Django projects. However, to set up additional global variables you need to work with Jinja's environment.

To set up Jinja globals you need to access Jinja's environment which is where globals are stored, in a variable properly called globals. By default, the Django-Jinja configuration uses Jinja's built-in jinja2.Environment environment. In order to access Jinja's environment in Django and set globals, the easiest path is to create your own Jinja environment and use it to initialize the Django-Jinja configuration. Listing 4-11 illustrate a custom Jinja environment class which sets the global variables named static and url.

Listing 4-11 Custom Jinja environment with global variable

from jinja2.environment import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.urlresolvers import reverse

class JinjaEnvironment(Environment):
    def __init__(self,**kwargs):
        super(JinjaEnvironment, self).__init__(**kwargs)
        self.globals['static'] = staticfiles_storage.url
        self.globals['url'] = reverse

As you can see in listing 4-11, the custom JinjaEnvironment class is a sub-class of the jinja2.Environment class, this is so the custom class inherits the bulk of its features from this base class provided by Jinja. Next, you can see we use the __init__ method to initialize the base class.

Prior to exiting the initialization method of the class, you can also see we access the globals variable of the instance. globals is composed of a dictionary, where the key-values correspond to the Jinja template variable names and values, respectively. In this case, we create the static variable and assigns it Django's django.contrib.staticfiles.storage.staticfiles_storage.url method. This gives the static global variable the same behavior as Django's staticfiles app, so that it's possible to declare static resources just like it's done in Django (e.g. Jinja can then do <img src="{{ static('images/background.png') }}" alt="Background">) -- a topic which is described in greater detail in chapter 5 on static resource management, but this is important to mention here due to the gap it fills in Jinja lacking functionality on this front.

The second global in listing 4-11 creates the url variable and assigns it Django's django.core.urlresolvers.reverse method. This gives the url global variable the same behavior as Django's {% url %} tag, so that it's possible to resolve a URL based on a name-- as described in the chapter two section Url naming and namespaces -- just like it's done in Django (e.g. Jinja can then do <a href="{{ url('homepage') }}">Go to homepage</a>) -- note this is another important gap to fill given Jinja's lack of functionality on this front.

Just as you can add these last two global variable to mimic the behavior of Django apps and tags that are missing in Jinja templates, you can add more globals in the same manner or increase the complexity of a Jinja global as needed.

Once the custom Jinja environment is ready, you need to set it up in Django's settings.py file so it's used to initialize Jinja. Listing 4-12 illustrates how to set up a custom Jinja environment in Django inside the TEMPLATES variable.

Listing 4-12. Configure custom Jinja environment in Django setttings.py

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
PROJECT_DIR = Path(__file__).resolve().parent

TEMPLATES = [
    { 
        'BACKEND':'django.template.backends.jinja2.Jinja2',
	'DIRS': [ PROJECT_DIR / 'jinjatemplates' ],	
        'APP_DIRS': True,
        'OPTIONS': { 
            'environment': 'coffeehouse.jinja.env.JinjaEnvironment'
            }
        },
    ]

The Jinja environment is set through the environment key, as part of the OPTIONS variable. The value of the environment key is a string with dot notation that points to a custom Jinja environment class. In this case, you can see the value corresponds to coffeehouse.jinja.env.JinjaEnvironment, where JinjaEnvironment is the class, env is the file/module name and coffeehouse.jinja is the directory path.

To better illustrate the location of the env.py file containing the custom Jinja environment, listing 4-13 illustrates a directory structure with additional Django project files for reference.

Listing 4-13 Directory structure and location of custom Jinja environment

+---+-<PROJECT_DIR_coffeehouse>
    |
    +-asgi.py    
    +-__init__.py
    +-settings.py
    +-urls.py
    +-wsgi.py
    |
    +-jinja-+
            +-__init__.py
            +-env.py

A with the placement and configuration of this Jinja environment in a Django project, all Jinja templates are able to use the static and url globals.