Introduction

In many Django projects, some data needs to appear on almost every page.

For example:

You could send this data manually from every view, but that quickly becomes repetitive and hard to maintain.

This is where context processors become very useful.

A context processor is a Python function that adds variables automatically to the context of all templates, or at least all templates rendered with Django’s standard template system.

In this tutorial, you will learn what context processors are, how they work, how to create custom ones, and how to use them in real Django projects.

What You Will Learn

By the end of this tutorial, you will understand:

Prerequisites

Before starting, you should already know:

1. The Problem Context Processors Solve

Suppose you want the site name available on every page.

Without a context processor, you might do this in every view:

def home(request):
    return render(request, 'home.html', {'site_name': 'MofidTech'})

And then again:

def about(request):
    return render(request, 'about.html', {'site_name': 'MofidTech'})

And again:

def contact(request):
    return render(request, 'contact.html', {'site_name': 'MofidTech'})

This becomes repetitive.

A context processor lets you define the variable once, and Django adds it automatically to every template context.

2. What Is a Context Processor?

A context processor is a function that:

Basic structure:

def my_context_processor(request):
    return {
        'my_variable': 'some value'
    }

Once registered in settings.py, this variable becomes available in templates automatically.

3. Built-In Context Processors in Django

Django already includes several built-in context processors.

Common ones include:

These are defined in your settings.py inside the TEMPLATES setting.

Example:

TEMPLATES = [
    {
        ...
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

4. What Built-In Context Processors Provide

request

Makes the current request object available in templates.

Example:

{{ request.path }}

auth

Makes authentication variables available.

Example:

{{ user.username }}
{% if user.is_authenticated %}
    Welcome back!
{% endif %}

messages

Makes Django messages available in templates.

Example:

{% for message in messages %}
    <p>{{ message }}</p>
{% endfor %}

5. Creating Your First Custom Context Processor

Let us create a simple one for the site name.

Step 1: Create a file

Inside your app, create a file called:

context_processors.py

Example structure

# your_app/context_processors.py

def site_info(request):
    return {
        'site_name': 'MofidTech'
    }

6. Register the Context Processor

Now add it to settings.py.

settings.py

TEMPLATES = [
    {
        ...
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'your_app.context_processors.site_info',
            ],
        },
    },
]

Now site_name is available in all templates.

7. Use It in a Template

Example in base.html:

<h1>{{ site_name }}</h1>

You do not need to pass site_name manually from the view anymore.

8. Another Example: Current Year in Footer

A common use case is the current year in the footer.

context_processors.py

from datetime import datetime

def current_year(request):
    return {
        'current_year': datetime.now().year
    }

Register in settings.py

'your_app.context_processors.current_year',

Template

<footer>
    <p>&copy; {{ current_year }} {{ site_name }}</p>
</footer>

9. Real Example: Categories in Navbar

Suppose you have a blog and want categories visible in the navbar on every page.

models.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

context_processors.py

from .models import Category

def global_categories(request):
    return {
        'global_categories': Category.objects.all()
    }

Template

<ul>
    {% for category in global_categories %}
        <li>{{ category.name }}</li>
    {% endfor %}
</ul>

Now categories appear everywhere without repeating code in every view.

10. Context Processor with Conditional Logic

You can also use logic inside a context processor.

Example: show unread notifications count only for authenticated users.

def notification_count(request):
    if request.user.is_authenticated:
        count = 5  # example placeholder
    else:
        count = 0

    return {
        'notification_count': count
    }

Template:

{% if user.is_authenticated %}
    <span>Unread: {{ notification_count }}</span>
{% endif %}

11. Example: Shopping Cart Count

A common e-commerce example:

def cart_data(request):
    cart = request.session.get('cart', [])
    return {
        'cart_count': len(cart)
    }

Template:

<a href="{% url 'cart' %}">
    Cart ({{ cart_count }})
</a>

Now the cart item count is always visible in the navbar.

12. Full Example of a Context Processor File

your_app/context_processors.py

from datetime import datetime
from .models import Category

def site_info(request):
    return {
        'site_name': 'MofidTech'
    }

def current_year(request):
    return {
        'current_year': datetime.now().year
    }

def global_categories(request):
    return {
        'global_categories': Category.objects.all()
    }

def cart_data(request):
    cart = request.session.get('cart', [])
    return {
        'cart_count': len(cart)
    }

This file can hold multiple context processors.

13. Registering Multiple Context Processors

settings.py

TEMPLATES = [
    {
        ...
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'your_app.context_processors.site_info',
                'your_app.context_processors.current_year',
                'your_app.context_processors.global_categories',
                'your_app.context_processors.cart_data',
            ],
        },
    },
]

14. When Context Processors Are Applied

Context processors are applied when using Django’s template rendering system, especially with:

return render(request, 'template.html', context)

They do not automatically apply to every type of response, such as raw HttpResponse content.

15. Context Processor vs Passing Context Manually

Manual context

return render(request, 'home.html', {
    'site_name': 'MofidTech'
})

Context processor

def site_info(request):
    return {'site_name': 'MofidTech'}

Use manual context when:

Use a context processor when:

16. Be Careful with Database Queries

Context processors run very often, because they are used in many templates.

So avoid heavy queries like:

def expensive_data(request):
    return {
        'all_posts': Post.objects.all(),
        'all_comments': Comment.objects.all(),
        'all_users': User.objects.all(),
    }

This can slow down every page.

Use context processors only for small, useful, globally needed data.

17. Good Use Cases for Context Processors

Great candidates include:

18. Bad Use Cases for Context Processors

Avoid using them for:

Those should usually stay in the view.

19. Example: Theme Preference from Cookie

You can also read cookies or sessions.

def theme_settings(request):
    return {
        'theme': request.COOKIES.get('theme', 'light')
    }

Template:

<body class="{{ theme }}">

This makes the theme value available on every page.

20. Example: Logged-In User Profile Info

If every page header shows the user’s city, you might do:

def user_profile_data(request):
    if request.user.is_authenticated and hasattr(request.user, 'profile'):
        return {
            'user_city': request.user.profile.city
        }
    return {
        'user_city': ''
    }

Template:

{% if user.is_authenticated %}
    <p>City: {{ user_city }}</p>
{% endif %}

This can be useful, but remember not to overload context processors with too much profile logic.

21. Common Beginner Mistakes

Forgetting to register the context processor

Creating the function is not enough. You must add it to settings.py.

Using the wrong import path

Example:

'your_app.context_processors.site_info'

must match the real app name and file location.

Returning something other than a dictionary

Wrong:

def site_info(request):
    return 'MofidTech'

Correct:

def site_info(request):
    return {'site_name': 'MofidTech'}

Doing expensive queries in every request

This can slow the whole site.

22. Best Practices

23. Mini Project Example

Imagine a blog layout where every page needs:

context_processors.py

from datetime import datetime
from .models import Category

def site_defaults(request):
    cart = request.session.get('cart', [])
    return {
        'site_name': 'MofidTech',
        'current_year': datetime.now().year,
        'global_categories': Category.objects.all(),
        'cart_count': len(cart),
    }

Register it

'your_app.context_processors.site_defaults',

base.html

<header>
    <h1>{{ site_name }}</h1>

    <nav>
        {% for category in global_categories %}
            <a href="#">{{ category.name }}</a>
        {% endfor %}
    </nav>

    <a href="{% url 'cart' %}">Cart ({{ cart_count }})</a>
</header>

<footer>
    <p>&copy; {{ current_year }} {{ site_name }}</p>
</footer>

This is a very realistic use case.

24. Summary

In this tutorial, you learned that:

Context processors are a simple but powerful way to keep Django templates cleaner and your project easier to maintain.

25. Mini Quiz

1. What does a context processor return?

A. A list
B. A string
C. A dictionary
D. A model

2. Where are context processors registered?

A. models.py
B. forms.py
C. settings.py
D. urls.py

3. Which built-in context processor makes user available in templates?

A. request
B. auth
C. messages
D. static

4. What kind of data is best for a context processor?

A. Very large datasets
B. Heavy reports
C. Global lightweight template data
D. Page-specific forms

5. Which file is commonly used to store custom context processors?

A. helpers.py
B. context_processors.py
C. template_tags.py
D. global.py

26. What Comes Next?

The next ideal tutorial is:

Tutorial : Custom Template Filters and Tags
Subject: creating reusable display logic inside Django templates.