Understanding context in Django

5 Dec 2020

category is ~ django ~ wagtail ~ python ~

Context is everything!

The more time you spend with Django, the more you'll see context everywhere.

At first, it seemed way too abstract for me to really get my head around, but it's actually crucial for passing data to the frontend of an application. The concept of "context" is not actually unique to Django — or even to backend programming as a whole — but here I'm just going to address what it means in Django.

Think of it like this: you need the frontend to show your backend data to users. But since they are separate entities and the frontend can't just receive the data as it is, the frontend is like, "Er, what are you talking about? I'm gonna need some context...?"

Let's jump right in with an example from the source of this very blog. The following model is for a blog index page, i.e. something like this, where all the blog posts are displayed.

N.B.: Regular Django applications will separate models and views. In Wagtail, however, which is where this snippet comes from, views in their own right are pretty much done away with. Instead, there tends to be a section of the model class that essentially stands in for a function-based view (commonly abbreviated as FBV).

class BlogIndexPage(Page):
    body = RichTextField(blank=True)

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        blogpages = BlogPage.objects.live().public().order_by("-date")

        if request.GET.get("tag", None):
            tags = request.GET.get("tag")
            blogpages = blogpages.filter(tags__slug__in=[tags])

        context["blogpages"] = blogpages
        return context


Note that Python's get() method returns a value for the given key — this is the syntax of the method: dict.get(key[value])

So, what happens when we look at the template for BlogIndexPage?


{% block content %}

  {% for post in blogpages %}
    {% with post=post.specific %}

      <h2><a href="{% pageurl post %}">{{ post.title|richtext }}</a></h2>

      {{ post.date }}

    {% endwith %}

  {% endfor %}

{% endblock %}

Django templates are actually HTML files, but you can use its built-in templating language and do cool stuff like for-loops just as you would in Python. So, bearing in mind that the blogpages context variable is a Python object, we can say that for each post in it, we want this and this to happen. In line 5, our context is already in action — blogpages is fetched. Additionally, we use Wagtail's own database method, specific() (note that in the template, the method call is rendered without the brackets), so that for each post instance the most specific data possible is retrieved. We then proceed to tell Django how we want various post attributes to be displayed — post.title, post.date, etc.

Context processors

The Django docs say:

context_processors is a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return a dict of items to be merged into the context. It defaults to an empty list.

In other words, a context processor is a method that takes a an argument (often request) and returns a dictionary.

Take a look at the TEMPLATES list in the settings.py file of your project. The following default Django context processors are there:

"context_processors": [

Any other custom context processors you make for your application will then have to be added here so that Django can find them when rendering a template. Here's a well-explained tutorial for making your own.

Context on the client side

Lately, I've taken a dip into the frontend and been trying to develop a separate, rudimentary UI for my Django application. As we've seen here already, context is important when it comes to communication between the backend and frontend. This merits its own post, though.

⟵ return to blog