Adding a Context Processor to a Django project
3 min read

Adding a Context Processor to a Django project

Adding a Context Processor to a Django project

Context processors provide information to templates. csrf_token is a context processor, for example, as is request. You can find the list of context processors configured in your settings.py file, under TEMPLATES.

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [TEMPLATE_DIR],
        "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",
                "config.context_processors.transfer_requests",
                "config.context_processors.location",
            ],
        },
    },
]

Here, we see debug, request, auth, messages, transfer_requests and location are all context processors available to templates in this project.

What are those last two though? They don't look like core Django modules!

Nope, they're extra ones I've added in for use in my project, and it's very easy to do.

Adding a customised context processor

Let's say you frequently need to know whether it's a Tuesday when you're building your templates. Sure, you could pass this in via the get_context_data method on the views every time you need it, or you could write one function, add it to your context processors, and have it available whenever you need it.

Add context_processors.py

To make life simple, keep your custom context processors in their own file, then define a function that will return your context data. A stub for this might look like this:

from django.utils.functional import SimpleLazyObject

def my_context_processor(request):  
    def context_data():
        return {"key": "value"}
    return {"my_context": SimpleLazyObject(context_data)}

You'll note that this returns the function as a lazy object, rather than the result of the function, which means the function will be evaluated when the template uses it.

So, let's check whether it's Tuesday!

from datetime import date
from django.utils.functional import SimpleLazyObject

def is_tuesday(request):  
    def today_is_tuesday():
        if date.today().weekday() == 1:
            return {"is_tuesday": True}
        return {"is_tuesday": False}
    return {"is_tuesday": SimpleLazyObject(today_is_tuesday)}

Making the new processor available

To do this, we add it to the TEMPLATES setting in settings.py as you saw above.

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [TEMPLATE_DIR],
        "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",
                "<appname>.context_processors.is_tuesday",
            ]
        }
    }
]

Et voilĂ , your new context processor is now available. Note that for <appname> above, it doesn't necessarily need to be an app. It could be the project module, or its own module within the project root. I usually create a module called config for this kind of thing that is useful across all the apps in a project, but that's just me.

Using the context in a template

This is the simplest part, as you use it just like any other bit of context data. In our case we might do:

{% if is_tuesday %}
    <h2>Cheer up, it's Tuesday! Hump day tomorrow!</h2>
{% endif %}

And now you can add a new context processor that will be available in all your templates.

One word of caution

Don't go overboard and start adding all your data this way. Remember that all this data is being sent with every request, whether the template needs it or not, so if you define context processors that return a lot of data, or just lots and lots of small context processors, be sure they're useful in a lot of places first.

If you have data that's only needed in one or two views, just factor out the code to a function and call that from get_context_data to keep your code DRY and your requests a little smaller.

Enjoying these posts? Subscribe for more