Bird
Raised Fist0
Djangoframework~8 mins

Creating custom middleware in Django - Performance Optimization Steps

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
Performance: Creating custom middleware
MEDIUM IMPACT
This affects the request-response cycle speed and server processing time, impacting how fast pages start loading.
Adding custom logic to process requests and responses
Django
class FastMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Minimal processing, no blocking calls
        response = self.get_response(request)
        return response
Avoids blocking calls and heavy processing, keeping request handling fast.
📈 Performance GainReduces blocking time to near 0ms, improving LCP
Adding custom logic to process requests and responses
Django
class SlowMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        import time
        time.sleep(1)  # Simulate slow processing
        response = self.get_response(request)
        return response
This middleware blocks the request for 1 second, delaying every page load.
📉 Performance CostBlocks rendering for 1000ms per request, increasing LCP significantly
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
Heavy blocking middleware0 (server-side)0 (client-side)0 (client-side)[X] Bad
Lightweight middleware0 (server-side)0 (client-side)0 (client-side)[OK] Good
Rendering Pipeline
Middleware runs on the server before the response is sent to the browser, affecting how quickly the browser can start rendering.
Server Processing
Network Transfer
Browser Rendering
⚠️ BottleneckServer Processing time caused by middleware logic
Core Web Vital Affected
LCP
This affects the request-response cycle speed and server processing time, impacting how fast pages start loading.
Optimization Tips
1Avoid blocking calls inside middleware to keep server response fast.
2Keep middleware logic simple and efficient to reduce delay.
3Use DevTools Network tab to monitor server response times.
Performance Quiz - 3 Questions
Test your performance knowledge
How does heavy processing in custom middleware affect page load?
AIt improves network speed
BIt increases server response time, delaying page load
CIt reduces browser paint time
DIt decreases DOM size
DevTools: Network
How to check: Open DevTools, go to Network tab, reload page, and check the Time column for server response delays.
What to look for: Look for long 'Waiting (TTFB)' times indicating slow server processing possibly caused by middleware.

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