Introduction
In many Django projects, some data needs to appear on almost every page.
For example:
- the site name in the navbar
- categories in the sidebar
- the logged-in user
- unread notifications count
- footer links
- shopping cart item count
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:
- what a context processor is
- why context processors are useful
- how Django’s built-in context processors work
- how to create a custom context processor
- how to register it in
settings.py - how to use context processor variables in templates
- best practices and common mistakes
Prerequisites
Before starting, you should already know:
- Django templates
- views and context dictionaries
- basic project settings
- template inheritance
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:
- receives the
request - returns a dictionary of variables
- makes those variables available in templates
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:
requestauthmessages
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.pyExample 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>© {{ 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.namecontext_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:
- data is specific to one page
- only one or two views need it
Use a context processor when:
- data is needed in many templates
- it belongs to global layout elements like navbar, footer, sidebar
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:
- site name
- footer year
- navbar categories
- cart count
- current theme
- unread notification count
- global settings
- social links
18. Bad Use Cases for Context Processors
Avoid using them for:
- large data lists
- page-specific results
- expensive database queries
- forms that only one page uses
- content that changes heavily per page
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
- use context processors only for truly global template data
- keep them lightweight
- avoid complex business logic
- avoid large querysets
- give variables clear names
- group related context processors in one fil
23. Mini Project Example
Imagine a blog layout where every page needs:
- site name
- all categories in navbar
- current year in footer
- cart count in top bar
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>© {{ current_year }} {{ site_name }}</p>
</footer>This is a very realistic use case.
24. Summary
In this tutorial, you learned that:
- context processors automatically add variables to templates
- they help avoid repeating common context data in every view
- Django already includes built-in context processors for
request,auth, andmessages - custom context processors are easy to create
- they must be registered in
settings.py - they are best for global, lightweight data such as site info, navbar items, and footer values
- they should not contain heavy database logic
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.
💬 Comments
No comments yet. Be the first to comment!
Login to comment.