Bird
Raised Fist0
Djangoframework~10 mins

Creating custom middleware in Django - Visual Walkthrough

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Creating custom middleware
Request comes in
Middleware __call__ or process_request
View function executes
Middleware process_response
Response sent back to client
Middleware intercepts requests before views and responses after views, allowing custom processing.
Execution Sample
Django
class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    def __call__(self, request):
        print('Before view')
        response = self.get_response(request)
        print('After view')
        return response
This middleware prints messages before and after the view runs for each request.
Execution Table
StepActionEvaluationResult
1Request received by middleware __call__Print 'Before view'Message logged: Before view
2Call get_response(request) to run viewView processes requestView returns HttpResponse
3After view returnsPrint 'After view'Message logged: After view
4Return response to clientResponse sentClient receives HttpResponse
5End of middleware processingNo further actionRequest cycle complete
💡 Response returned to client after middleware and view processing
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
requestHttpRequest objectSame HttpRequestSame HttpRequestSame HttpRequestSame HttpRequest
responseNoneNoneHttpResponse from viewHttpResponse from viewHttpResponse from view
Key Moments - 2 Insights
Why do we call self.get_response(request) inside __call__?
Calling self.get_response(request) runs the next middleware or the view. Without it, the request would stop and no response would be generated. See execution_table step 2.
What happens if we modify the response after calling get_response?
You can change the response before returning it to the client. This happens after the view runs, as shown in execution_table step 3.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is printed before the view runs?
A'Request received'
B'After view'
C'Before view'
D'Response sent'
💡 Hint
Check step 1 in the execution_table where the first print happens.
At which step does the view function execute?
AStep 2
BStep 1
CStep 3
DStep 4
💡 Hint
Look at the action in step 2 where get_response(request) is called.
If we remove the call to self.get_response(request), what happens?
AThe middleware prints both messages
BNo response is returned to the client
CThe view still runs normally
DThe response is sent twice
💡 Hint
Refer to key_moments about why get_response(request) is necessary.
Concept Snapshot
Creating custom middleware in Django:
- Define a class with __init__(get_response) and __call__(request)
- __call__ runs code before and after calling get_response(request)
- get_response(request) calls the next middleware or view
- Modify request before or response after view
- Return the final response to complete the cycle
Full Transcript
In Django, custom middleware is a class that intercepts requests and responses. When a request comes in, the middleware's __call__ method runs. It can do something before the view by running code before calling get_response(request). Then it calls get_response(request) to run the view or next middleware. After the view returns a response, the middleware can modify or log after the view. Finally, it returns the response to the client. This lets you add custom behavior around every request and response cycle.

Practice

(1/5)
1. What is the main purpose of custom middleware in Django?
easy
A. To run code before and after a view processes a request
B. To define database models
C. To create HTML templates
D. To handle user authentication only

Solution

  1. Step 1: Understand middleware role

    Middleware runs code before and after views handle requests.
  2. 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.
  3. Final Answer:

    To run code before and after a view processes a request -> Option A
  4. Quick Check:

    Middleware = pre/post view code [OK]
Hint: Middleware runs code around views, not models or templates [OK]
Common Mistakes:
  • Confusing middleware with models or templates
  • Thinking middleware only handles authentication
  • Believing middleware runs only after views
2. Which method must a Django custom middleware class implement to process requests and responses?
easy
A. __call__
B. __init__
C. process_request
D. handle_request

Solution

  1. Step 1: Recall middleware class structure

    Custom middleware uses __init__ for setup and __call__ to handle requests and responses.
  2. Step 2: Identify correct method for processing

    __call__ is the method that processes requests and responses; others are incorrect or deprecated.
  3. Final Answer:

    __call__ -> Option A
  4. Quick Check:

    Middleware processing method = __call__ [OK]
Hint: Use __call__ to process requests in custom middleware [OK]
Common Mistakes:
  • Using process_request which is old style
  • Confusing __init__ with request processing
  • Inventing non-existent methods like handle_request
3. Given this middleware code, what will be printed when a request is processed?
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
medium
A. After view\nBefore view\nMiddleware initialized
B. Middleware initialized\nBefore view\nAfter view
C. Before view\nAfter view\nMiddleware initialized
D. Middleware initialized only

Solution

  1. Step 1: Understand when __init__ runs

    __init__ runs once when middleware is created, printing 'Middleware initialized'.
  2. Step 2: Trace __call__ execution order

    __call__ prints 'Before view', calls the view, then prints 'After view'.
  3. Final Answer:

    Middleware initialized\nBefore view\nAfter view -> Option B
  4. Quick Check:

    Init then before and after view prints [OK]
Hint: Init prints once; __call__ prints before and after view [OK]
Common Mistakes:
  • Thinking __init__ runs on every request
  • Mixing order of print statements
  • Ignoring that __call__ wraps the view call
4. What is wrong with this custom middleware code?
class MyMiddleware:
    def __init__(self):
        pass

    def __call__(self, request):
        response = self.get_response(request)
        return response
medium
A. No error, code is correct
B. __call__ should not return a response
C. Missing get_response parameter in __init__
D. Middleware classes cannot have __call__ method

Solution

  1. Step 1: Check __init__ signature

    Middleware __init__ must accept get_response parameter to store it for later use.
  2. Step 2: Identify missing attribute

    get_response is used in __call__, but not saved in __init__, causing an error.
  3. Final Answer:

    Missing get_response parameter in __init__ -> Option C
  4. Quick Check:

    __init__ needs get_response [OK]
Hint: Always accept get_response in __init__ for middleware [OK]
Common Mistakes:
  • Omitting get_response parameter
  • Not storing get_response as instance variable
  • Thinking __call__ cannot return response
5. You want to create a custom middleware that adds a header 'X-Hello: World' to every response. Which code snippet correctly implements this?
hard
A. class HelloMiddleware: def __init__(self, get_response): self.get_response = get_response def process_response(self, request, response): response['X-Hello'] = 'World' return response
B. class HelloMiddleware: def __init__(self): pass def __call__(self, request): response = self.get_response(request) response.headers.add('X-Hello', 'World') return response
C. class HelloMiddleware: def __call__(self, request): response = self.get_response(request) response['X-Hello'] = 'World' return response
D. 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

Solution

  1. 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__.
  2. 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.
  3. 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.
  4. 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 D
  5. Quick Check:

    New middleware = __init__ + __call__ + modify response [OK]
Hint: New middleware needs get_response in __init__ and modifies response in __call__ [OK]
Common Mistakes:
  • Omitting get_response in __init__
  • Using old process_response method
  • Trying to add headers before calling get_response