Real-world examples of examples of Django middleware example patterns

If you’re working with Django in 2024, you can’t get far without bumping into middleware. And the best way to understand it is by walking through real, working code. In this guide, we’ll focus on practical, real-world examples of examples of Django middleware example patterns that you can drop into your projects today. Instead of vague theory, you’ll see how middleware behaves in the request/response cycle and how to wire it into modern Django settings. We’ll look at an example of logging middleware, security headers, API timing, feature flags, and more. These are the kinds of middleware examples you actually see in production SaaS apps, internal dashboards, and public APIs. Along the way, we’ll call out best practices for Django 4.x and 5.x, show you how to avoid common performance traps, and highlight where middleware still makes sense compared to views, signals, or DRF throttling. By the end, you’ll have several concrete examples you can adapt for your own stack.
Written by
Jamie
Published

Starting with real examples of Django middleware

Let’s skip the abstract theory and jump straight into code. The most helpful examples of examples of Django middleware example patterns are the ones you can paste into middleware.py, wire into MIDDLEWARE, and see in your logs immediately.

Below, we’ll walk through several real examples:

  • Request/response logging
  • Execution time profiling
  • Security headers
  • Maintenance mode banner
  • Feature flags from headers
  • Simple IP allow/deny list
  • Correlation IDs for tracing
  • Content negotiation for JSON-only APIs

Each example of Django middleware will show:

  • A minimal class-based middleware implementation
  • How it plugs into Django’s middleware stack
  • Where it fits in a modern 2024–2025 architecture

Logging middleware: the classic example of request tracing

One of the best examples of Django middleware in real projects is a lightweight request logger. You want basic telemetry without dragging in a full observability platform on day one.

## core/middleware.py
import time
import logging

logger = logging.getLogger(__name__)

class RequestLoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        start = time.monotonic()
        response = self.get_response(request)
        duration = (time.monotonic() - start) * 1000  # ms

        logger.info(
            "method=%s path=%s status=%s duration_ms=%.2f user=%s",
            request.method,
            request.path,
            getattr(response, 'status_code', 'unknown'),
            duration,
            getattr(request.user, 'id', None),
        )

        return response

Add it to your settings.py:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
#    # ...
    "core.middleware.RequestLoggingMiddleware",
]

Real examples include using this in:

  • Internal admin tools to spot slow endpoints
  • Early-stage APIs before adopting OpenTelemetry
  • Debug environments where you need clear per-request logs

This is one of the clearest examples of examples of Django middleware example snippets: tiny, focused, and obviously useful.


Execution time profiling: examples include per-view timing

Sometimes logging status codes isn’t enough. You want an example of middleware that helps you hunt down slow views without attaching a full profiler.

## core/middleware.py
import time
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin

class SimpleTimingMiddleware(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        request._view_start_time = time.perf_counter()

    def process_template_response(self, request, response):
        start = getattr(request, "_view_start_time", None)
        if start is not None and settings.DEBUG:
            duration = (time.perf_counter() - start) * 1000
            response["X-View-Duration-ms"] = f"{duration:.2f}"
        return response

In 2024 and 2025, this pattern pairs nicely with browser dev tools and API clients like Insomnia or Postman. You can sort calls by the X-View-Duration-ms header and quickly see slow views.

This is one of the best examples of Django middleware when you want performance insight without changing your views or templates.


Security headers middleware: modern hardening examples

Django ships with good defaults, but real-world deployments often need stricter headers. The following example of middleware adds common security headers that many production apps use:

## security/middleware.py
class SecurityHeadersMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)

        response.setdefault("X-Content-Type-Options", "nosniff")
        response.setdefault("X-Frame-Options", "DENY")
        response.setdefault("Referrer-Policy", "strict-origin-when-cross-origin")
        response.setdefault("Permissions-Policy", "geolocation=(), microphone=()")

        return response

You’d usually place this after Django’s own SecurityMiddleware:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
#    # ...
    "security.middleware.SecurityHeadersMiddleware",
]

Real examples include SaaS dashboards that must satisfy security questionnaires or internal security reviews. For deeper background on the intent behind headers like these, the OWASP Foundation maintains updated guidance on web security patterns at https://owasp.org.

Again, this is one of those examples of examples of Django middleware example snippets that’s small but has an outsized impact on your security posture.


Maintenance mode banner: user-facing examples of Django middleware

Sometimes you need a soft maintenance mode rather than a full 503 outage page. An example of this is a middleware that injects a banner for authenticated users when you’re about to deploy a breaking change.

## core/middleware.py
from django.conf import settings

class MaintenanceBannerMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)

        if (
            getattr(settings, "MAINTENANCE_BANNER", "")
            and hasattr(response, "context_data")
        ):
            response.context_data["maintenance_banner"] = settings.MAINTENANCE_BANNER

        return response

In your settings:

MAINTENANCE_BANNER = "Scheduled downtime at 11:00 PM Eastern. Expect brief interruptions."

Then, in your base template:

{% if maintenance_banner %}
  <div class="banner banner-warning">{{ maintenance_banner }}</div>
{% endif %}

Real examples include internal tools at universities, hospitals, or government agencies where you must warn staff before planned updates. While health-focused agencies like the CDC or NIH don’t publish Django-specific code, their public sites often show similar UX patterns: clear, visible notices when systems are changing or data is being updated.


Feature flag middleware: examples include header-based toggles

As apps grow, you often need feature flags. Many teams reach for third-party services, but a simple example of Django middleware can cover basic needs.

## core/middleware.py
class HeaderFeatureFlagMiddleware:
    """Enable experimental features via HTTP header.

    Example: X-Features: new_dashboard,fast_search
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        raw = request.headers.get("X-Features", "")
        flags = {flag.strip() for flag in raw.split(",") if flag.strip()}
        request.feature_flags = flags
        return self.get_response(request)

In your views:

def dashboard(request):
    if "new_dashboard" in getattr(request, "feature_flags", set()):
        return render(request, "dashboard/new.html")
    return render(request, "dashboard/old.html")

This is one of the best examples of Django middleware for staging environments, QA, or power users. Product managers can send specific headers from their browser or API client to see new behavior without affecting everyone.


IP allow/deny list: security-focused examples of Django middleware

When you host admin tools or internal APIs, you often want a simple IP restriction in front of Django’s authentication. A common example of middleware looks like this:

## security/middleware.py
from django.conf import settings
from django.http import HttpResponseForbidden

class IPAllowListMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.allowed_ips = set(getattr(settings, "ALLOWED_IPS", []))

    def __call__(self, request):
        if not self.allowed_ips:
            return self.get_response(request)

        ip = request.META.get("REMOTE_ADDR")
        if ip not in self.allowed_ips:
            return HttpResponseForbidden("Access denied.")

        return self.get_response(request)

In settings:

ALLOWED_IPS = ["127.0.0.1", "203.0.113.10"]

Real examples include intranet-style dashboards at universities (think of something like an internal system at Harvard, though they don’t publish their exact Django configs). The pattern is straightforward but effective as a first line of defense.

This is another one of those examples of examples of Django middleware example patterns that are simple but widely used.


Correlation ID middleware: tracing examples in distributed systems

In 2024–2025, it’s common to see Django apps as part of a larger microservice or service-oriented architecture. Logging needs a way to tie together a user’s journey across services. A practical example of Django middleware uses correlation IDs.

## observability/middleware.py
import uuid

class CorrelationIdMiddleware:
    HEADER_NAME = "X-Correlation-ID"

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        cid = request.headers.get(self.HEADER_NAME) or str(uuid.uuid4())
        request.correlation_id = cid

        response = self.get_response(request)
        response[self.HEADER_NAME] = cid
        return response

Now your logs, background tasks, and downstream services can all share the same ID. Real examples include large healthcare platforms that must trace requests end to end while complying with strict privacy requirements. While you won’t find their internal Django code on sites like Mayo Clinic or WebMD, the architectural idea is the same: traceability without leaking sensitive data.


JSON-only API middleware: content negotiation examples

Another frequent example of Django middleware is enforcing JSON APIs. If you’re building an API-only backend, you might want to reject HTML form posts and ensure clients send and receive JSON.

## api/middleware.py
from django.http import JsonResponse

class EnforceJSONMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path.startswith("/api/") and request.method in {"POST", "PUT", "PATCH"}:
            content_type = request.META.get("CONTENT_TYPE", "").split(";")[0]
            if content_type not in {"application/json", ""}:  # allow empty for some clients
                return JsonResponse(
                    {"error": "Only application/json is allowed."},
                    status=415,
                )

        response = self.get_response(request)

        if request.path.startswith("/api/"):
            response["Content-Type"] = "application/json; charset=utf-8"
        return response

Real examples include internal APIs used by mobile apps or single-page frontends where HTML responses are never needed.

This brings us to an interesting meta-point: many of the best examples of Django middleware from 2015 still work in 2025, but the context changed. Today, middleware tends to focus on cross-cutting concerns like observability, security, and protocol enforcement, while business logic lives in views, serializers, or async workers.

Collectively, these are strong examples of examples of Django middleware example patterns that align with current Django 4.x/5.x practices.


When to write middleware vs something else

Seeing these real examples, it’s tempting to throw everything into middleware. That’s not always the right call.

Middleware shines when:

  • The behavior applies to many or all requests
  • You need access before URL resolution or after the response is built
  • You’re adding headers, logging, or light request/response transformations

You’re usually better off using views, decorators, or DRF features when:

  • Logic is specific to a single endpoint or small group of views
  • You need detailed knowledge of serializers or models
  • You’re implementing business rules rather than infrastructure concerns

The examples of examples of Django middleware example snippets above are intentionally infrastructure-focused: logging, security, flags, IP filtering, and content rules.

For more general web development best practices that intersect with Django (security, privacy, accessibility), organizations like the OWASP Foundation and major public institutions such as NIH.gov publish guidance that influences how many teams design and secure their middleware.


FAQ: examples of Django middleware in practice

Q: What are some common examples of Django middleware used in production?
Common examples include request logging, execution time profiling, correlation ID injection, IP allow/deny lists, security headers, maintenance banners, feature flag headers, and JSON-only API enforcement. The examples of Django middleware earlier in this article cover each of these with concrete code.

Q: How do I decide if something should be middleware or a view decorator?
If the logic applies to almost every request (logging, tracing, security headers), middleware is usually a good fit. If it only applies to a few views, a decorator or mixin is often cleaner. Look back at the feature flag and IP allow list examples of Django middleware; those could be decorators for a small set of views, but middleware wins when you want global behavior.

Q: Can you give an example of middleware that should not contain business logic?
Yes. Imagine a rule like “patients over 65 see a different dashboard.” Even though you might be inspired by healthcare sites such as Mayo Clinic or WebMD, that age-based rule is business logic. It belongs in your views or service layer, not in middleware. Middleware should stay focused on cross-cutting concerns like the examples of logging, security, and content handling shown above.

Q: Are these examples of Django middleware compatible with Django 5.x?
Yes. All the class-based examples here follow the current middleware style that’s been stable since Django 1.10. As long as you avoid the old MIDDLEWARE_CLASSES setting and stick to the modern MIDDLEWARE stack, these patterns work in recent Django versions.

Q: Where can I find more real examples of Django middleware?
Open-source projects on GitHub are a gold mine. Search for middleware.py in well-maintained Django repos, and you’ll see variations on the examples include logging, security headers, and tracing. Combine that with general web security guidance from OWASP and public institutions, and you’ll have more than enough inspiration.

Explore More Django Code Snippets

Discover more examples and insights in this category.

View All Django Code Snippets