What if you could control every web request with just one simple piece of code?
Creating custom middleware in Django - Why You Should Know This
Start learning this pattern below
Jump into concepts and practice - no test required
Imagine you want to check every web request to your Django app for a special token or log details before the page loads.
You try adding this check inside every view function manually.
Manually adding checks in every view is tiring and easy to forget.
It leads to repeated code and bugs if you miss a spot.
Updating the logic means changing many places, which wastes time and causes errors.
Custom middleware lets you write one piece of code that runs automatically on every request or response.
This keeps your code clean, consistent, and easy to update.
def my_view(request): if not check_token(request): return error_response() # rest of view code
class TokenCheckMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): if not check_token(request): return error_response() response = self.get_response(request) return response
You can control and modify all requests and responses in one place, making your app more secure and maintainable.
Many websites use middleware to log user activity or block bad requests before they reach the main app logic.
Manual checks in every view cause repeated code and errors.
Custom middleware runs code automatically on all requests.
This makes your app easier to maintain and more reliable.
Practice
Solution
Step 1: Understand middleware role
Middleware runs code before and after views handle requests.Step 2: Compare options
Only To run code before and after a view processes a request describes middleware's purpose correctly; others describe unrelated tasks.Final Answer:
To run code before and after a view processes a request -> Option AQuick Check:
Middleware = pre/post view code [OK]
- Confusing middleware with models or templates
- Thinking middleware only handles authentication
- Believing middleware runs only after views
Solution
Step 1: Recall middleware class structure
Custom middleware uses __init__ for setup and __call__ to handle requests and responses.Step 2: Identify correct method for processing
__call__ is the method that processes requests and responses; others are incorrect or deprecated.Final Answer:
__call__ -> Option AQuick Check:
Middleware processing method = __call__ [OK]
- Using process_request which is old style
- Confusing __init__ with request processing
- Inventing non-existent methods like handle_request
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
print('Middleware initialized')
def __call__(self, request):
print('Before view')
response = self.get_response(request)
print('After view')
return response
Solution
Step 1: Understand when __init__ runs
__init__ runs once when middleware is created, printing 'Middleware initialized'.Step 2: Trace __call__ execution order
__call__ prints 'Before view', calls the view, then prints 'After view'.Final Answer:
Middleware initialized\nBefore view\nAfter view -> Option BQuick Check:
Init then before and after view prints [OK]
- Thinking __init__ runs on every request
- Mixing order of print statements
- Ignoring that __call__ wraps the view call
class MyMiddleware:
def __init__(self):
pass
def __call__(self, request):
response = self.get_response(request)
return response
Solution
Step 1: Check __init__ signature
Middleware __init__ must accept get_response parameter to store it for later use.Step 2: Identify missing attribute
get_response is used in __call__, but not saved in __init__, causing an error.Final Answer:
Missing get_response parameter in __init__ -> Option CQuick Check:
__init__ needs get_response [OK]
- Omitting get_response parameter
- Not storing get_response as instance variable
- Thinking __call__ cannot return response
Solution
Step 1: Confirm __init__ accepts get_response
class HelloMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) response['X-Hello'] = 'World' return response correctly accepts and stores get_response in __init__.Step 2: Check __call__ modifies response
class HelloMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) response['X-Hello'] = 'World' return response calls get_response, adds header, and returns response properly.Step 3: Identify errors in other options
class HelloMiddleware: def __init__(self): pass def __call__(self, request): response = self.get_response(request) response.headers.add('X-Hello', 'World') return response misses get_response in __init__; class HelloMiddleware: def __call__(self, request): response = self.get_response(request) response['X-Hello'] = 'World' return response misses __init__; class HelloMiddleware: def __init__(self, get_response): self.get_response = get_response def process_response(self, request, response): response['X-Hello'] = 'World' return response uses old process_response method not supported in new style middleware.Final Answer:
class HelloMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) response['X-Hello'] = 'World' return response -> Option DQuick Check:
New middleware = __init__ + __call__ + modify response [OK]
- Omitting get_response in __init__
- Using old process_response method
- Trying to add headers before calling get_response
