← Back to Django Course | Chapter 12: Signals & Middleware | Lesson 6 of 8

Writing Custom Middleware

Writing custom middleware means building your own checkpoint that every request has to pass through.

The Minimal Middleware Shape

Every middleware class needs an __init__ that stores get_response, and a __call__ that invokes it and returns the response.

Example: The Minimal Middleware Shape

Every middleware class needs an __init__ that stores get_response, and a __call__ that invokes it and returns the response.

markup
class MinimalMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

Adding Logic Before the View

Code placed before self.get_response(request) runs on the way in, and can attach extra data onto the request object for views to use later.

Example: Adding Logic Before the View

Code placed before self.get_response(request) runs on the way in, and can attach extra data onto the request object for views to use later.

markup
class RequestTaggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        request.is_mobile = "Mobile" in request.META.get("HTTP_USER_AGENT", "")
        return self.get_response(request)
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

Adding Logic After the View

Code placed after self.get_response(request) runs on the way out, and can inspect or modify the response before it reaches the browser.

Example: Adding Logic After the View

Code placed after self.get_response(request) runs on the way out, and can inspect or modify the response before it reaches the browser.

markup
class CustomHeaderMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        response["X-Powered-By"] = "Django"
        return response
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

Registering Your Middleware

A custom middleware class does nothing until its dotted path is added to the MIDDLEWARE list in settings.py.

Example: Registering Your Middleware

A custom middleware class does nothing until its dotted path is added to the MIDDLEWARE list in settings.py.

markup
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "myapp.middleware.CustomHeaderMiddleware",
]
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}
Common Mistakes
  1. Forgetting to return the response from __call__, which breaks every request in the project.
  2. Not calling self.get_response(request), which stops the view from ever running.
  3. Putting middleware logic in __init__ instead of __call__, so it only runs once at server startup instead of per request.
Chapter Summary
  • Custom middleware is a class with __init__(self, get_response) and __call__(self, request).
  • Always call self.get_response(request) and return its result to keep the chain working.
  • Register custom middleware by adding its dotted path to MIDDLEWARE in settings.py.
  • Per-request logic belongs in __call__, not __init__.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.