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.
By the end of this tutorial, you will understand:
settings.pyBefore starting, you should already know:
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.
A context processor is a function that:
requestBasic structure:
def my_context_processor(request):
return {
'my_variable': 'some value'
}Once registered in settings.py, this variable becomes available in templates automatically.
Django already includes several built-in context processors.
Common ones include:
requestauthmessagesThese 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',
],
},
},
]requestMakes the current request object available in templates.
Example:
{{ request.path }}authMakes authentication variables available.
Example:
{{ user.username }}
{% if user.is_authenticated %}
Welcome back!
{% endif %}messagesMakes Django messages available in templates.
Example:
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}Let us create a simple one for the site name.
Inside your app, create a file called:
context_processors.py# your_app/context_processors.py
def site_info(request):
return {
'site_name': 'MofidTech'
}Now add it to settings.py.
settings.pyTEMPLATES = [
{
...
'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.
Example in base.html:
<h1>{{ site_name }}</h1>You do not need to pass site_name manually from the view anymore.
A common use case is the current year in the footer.
context_processors.pyfrom datetime import datetime
def current_year(request):
return {
'current_year': datetime.now().year
}settings.py'your_app.context_processors.current_year',<footer>
<p>© {{ current_year }} {{ site_name }}</p>
</footer>Suppose you have a blog and want categories visible in the navbar on every page.
models.pyfrom django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.namecontext_processors.pyfrom .models import Category
def global_categories(request):
return {
'global_categories': Category.objects.all()
}<ul>
{% for category in global_categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>Now categories appear everywhere without repeating code in every view.
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 %}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.
your_app/context_processors.pyfrom 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.
settings.pyTEMPLATES = [
{
...
'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',
],
},
},
]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.
return render(request, 'home.html', {
'site_name': 'MofidTech'
})def site_info(request):
return {'site_name': 'MofidTech'}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.
Great candidates include:
Avoid using them for:
Those should usually stay in the view.
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.
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.
Creating the function is not enough. You must add it to settings.py.
Example:
'your_app.context_processors.site_info'must match the real app name and file location.
Wrong:
def site_info(request):
return 'MofidTech'Correct:
def site_info(request):
return {'site_name': 'MofidTech'}This can slow the whole site.
Imagine a blog layout where every page needs:
context_processors.pyfrom 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),
}'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>© {{ current_year }} {{ site_name }}</p>
</footer>This is a very realistic use case.
In this tutorial, you learned that:
request, auth, and messagessettings.pyContext processors are a simple but powerful way to keep Django templates cleaner and your project easier to maintain.
A. A list
B. A string
C. A dictionary
D. A model
A. models.py
B. forms.py
C. settings.py
D. urls.py
user available in templates?A. request
B. auth
C. messages
D. static
A. Very large datasets
B. Heavy reports
C. Global lightweight template data
D. Page-specific forms
A. helpers.py
B. context_processors.py
C. template_tags.py
D. global.py
The next ideal tutorial is:
Tutorial : Custom Template Filters and Tags
Subject: creating reusable display logic inside Django templates.