Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused by middleware execution process, DJANGO

Suppose I have the following class, as inspired by the Django documentation:

class SimpleMiddleware(object):

    def __ init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):


        response = self.get_response(request)

  
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):

        return None

When reading Daniel Rubio's book 'Beginning Django', he explains that the order of execution is:

  1. __ init __ method triggered (on server startup)
  2. __ call __ method triggered (on every request)
  3. If declared, process_view() method triggered
  4. View method starts with self.get_response(request) statement in __ call __

What exactly does "__ call __ method triggered (on every request)" mean? Does not 'triggering' the __ call __ method actually trigger 'self.get_respone(request)' automatically, thus calling either another middleware or a class?

The Django documentation states that:

process_view() is called just before Django calls the view.`

To me, this would have to mean that Django checks if the instance of the 'SimpleMiddleware' class contains a method 'process_view()' and then triggers that, before moving on to calling the __ call __() method, which 'calls the view'? Otherwise, if the __ call __ method is triggered immediately, won't 'process_view()' be missed since the __ call __ method calls the view (or the next middleware)?

Could someone please help me understand the execution process? How does Django go about this?

Thank you

like image 749
William Karlsson Avatar asked Jan 29 '23 15:01

William Karlsson


1 Answers

You are mixing up old style (pre django 1.10) and new style middlewares. The new style looks as follows:

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # do stuff with request
        response = self.get_response(request)
        # do stuff with request and/or response
        return response

The old style equivalent of that was:

class SimpleMiddleware:
    def process_request(self, request):
        # do stuff with request
    def process_response(self, request, response):
        # do stuff with request and/or response

In order to make it easier to port old code to the new way of doing things, django has added the MiddlewareMixin (source):

class MiddlewareMixin:
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        response = response or self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

All you have to do now with your old style middlewares is to make them subclass this mixin. But generally, new style middlewares do not per se have or need the process_... methods. But e.g.:

from django.utils.deprecation import MiddlewareMixin

class SimpleMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # do stuff with request
    def process_response(self, request, response):
        # do stuff with request and/or response

will work in both worlds.

like image 153
user2390182 Avatar answered Feb 11 '23 22:02

user2390182