Django Context Processors

Adding global variables to all templates

đŸŽ¯ What are Context Processors?

Context processors add variables to the template context automatically for every template. They make data available globally without passing it from every view, perfect for site-wide information like user data or settings.


# Simple context processor
def site_info(request):
    return {
        'site_name': 'My Website',
        'year': 2024
    }
                                    

Built-in Context Processors

🔐

auth

Provides user and permissions

'django.contrib.auth.context_processors.auth'

# Available in templates:
# {{ user }}
# {{ perms }}
🌐

request

Adds request object to context

'django.template.context_processors.request'

# Available in templates:
# {{ request.path }}
# {{ request.user }}
đŸ’Ŧ

messages

Provides message framework

'django.contrib.messages.context_processors.messages'

# Available in templates:
# {{ messages }}
📱

media

Adds MEDIA_URL to context

'django.template.context_processors.media'

# Available in templates:
# {{ MEDIA_URL }}

🔹 Creating Custom Context Processor

Context processors are simple functions that return dictionaries. The keys become variable names available in all templates, making it easy to share common data across your entire site.

# context_processors.py
from django.conf import settings

def site_settings(request):
    """Add site-wide settings to all templates"""
    return {
        'SITE_NAME': 'My Awesome Site',
        'SITE_TAGLINE': 'Building amazing things',
        'CONTACT_EMAIL': '[email protected]',
        'CURRENT_YEAR': 2024,
    }

def user_info(request):
    """Add user-specific information"""
    if request.user.is_authenticated:
        return {
            'unread_messages': request.user.messages.filter(read=False).count(),
            'user_avatar': request.user.profile.avatar.url,
        }
    return {}

Now Available in All Templates:

{{ SITE_NAME }} → "My Awesome Site"

{{ CURRENT_YEAR }} → 2024

{{ unread_messages }} → 5

🔹 Registering Context Processors

Add your context processor to the TEMPLATES setting in settings.py. Django will automatically call these functions for every template render.

# settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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',
                'myapp.context_processors.site_settings',  # Your custom processor
                'myapp.context_processors.user_info',      # Another custom processor
            ],
        },
    },
]

🔹 Using Context Variables in Templates

Once registered, context processor variables are automatically available in all templates without passing them from views.

<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{{ SITE_NAME }} - {{ SITE_TAGLINE }}</title>
</head>
<body>
    <header>
        <h1>{{ SITE_NAME }}</h1>
        {% if user.is_authenticated %}
            <p>Welcome, {{ user.username }}!</p>
            <p>You have {{ unread_messages }} unread messages</p>
        {% endif %}
    </header>
    
    <footer>
        <p>Š {{ CURRENT_YEAR }} {{ SITE_NAME }}</p>
        <p>Contact: {{ CONTACT_EMAIL }}</p>
    </footer>
</body>
</html>

Rendered Output:

My Awesome Site - Building amazing things

Welcome, john_doe!

You have 5 unread messages

Š 2025 My Awesome Site

Contact: [email protected]

🔹 Practical Example: Navigation Menu

Create a context processor that provides navigation menu items to all templates, making it easy to maintain consistent navigation across your site.

# context_processors.py
def navigation(request):
    """Provide navigation menu items"""
    menu_items = [
        {'name': 'Home', 'url': '/', 'icon': '🏠'},
        {'name': 'About', 'url': '/about/', 'icon': 'â„šī¸'},
        {'name': 'Blog', 'url': '/blog/', 'icon': '📝'},
        {'name': 'Contact', 'url': '/contact/', 'icon': '📧'},
    ]
    
    # Add admin link for staff users
    if request.user.is_staff:
        menu_items.append({
            'name': 'Admin', 
            'url': '/admin/', 
            'icon': 'âš™ī¸'
        })
    
    return {
        'nav_menu': menu_items,
        'current_path': request.path,
    }
<!-- Template usage -->
<nav>
    <ul>
    {% for item in nav_menu %}
        <li class="{% if current_path == item.url %}active{% endif %}">
            <a href="{{ item.url }}">
                {{ item.icon }} {{ item.name }}
            </a>
        </li>
    {% endfor %}
    </ul>
</nav>

Rendered Navigation:

🏠 Home | â„šī¸ About | 📝 Blog | 📧 Contact | âš™ī¸ Admin

🔹 Performance Considerations

Context processors run on every template render, so keep them efficient:

  • Avoid database queries: Cache results or use select_related
  • Keep it lightweight: Only add essential data
  • Use caching: Cache expensive computations
  • Conditional logic: Only compute what's needed
# Good: Efficient context processor
from django.core.cache import cache

def cached_stats(request):
    stats = cache.get('site_stats')
    if not stats:
        stats = {
            'total_users': User.objects.count(),
            'total_posts': Post.objects.count(),
        }
        cache.set('site_stats', stats, 300)  # Cache for 5 minutes
    return stats

🧠 Test Your Knowledge

What do context processors return?