start

As we learned in the previous section, WSGI can forward request information to our application.

We’ve already seen this, how it works, and how requests are handled. In this section, we’ll focus on how Django handles requests forwarded by WSGI.

start

# django.core.handlers.wsgi.py

class WSGIHandler(base.BaseHandler) :
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs) :
        super().__init__(*args, **kwargs)
        self.load_middleware()

    def __call__(self, environ, start_response) :
        """ The request will be forwarded here. """
        # seems to be suffixed with 'URL'
        set_script_prefix(get_script_name(environ))
        # send the incoming signal. We will cover the registration and processing of the signal in a later chapter
        signals.request_started.send(sender=self.__class__, environ=environ)
        The request object handling class is -> WSGIRequest
        request = self.request_class(environ)

        # underline -> What happens behind the scenes? (If the subclass does not have one, look in the parent class.)
        response = self.get_response(request)

        # After the above explanation is over, the guest officer continues to look down (code has been omitted)....Copy the code

Then the plot moves on to the get_response method.

# django.core.handlers.base.py BaseHandler

class BaseHandler:
    _view_middleware = None
    _template_response_middleware = None
    _exception_middleware = None
    _middleware_chain = None

    def get_response(self, request) :
        # set the url resolver. We don't care what happens inside.
        This is ready for subsequent route matching
        set_urlconf(settings.ROOT_URLCONF)

        What is the # _MIDDLEWARE_chain method...
        This property is assigned to a call to 'load_middleware'
        # Let's shift our focus to 'load_middleware'...
        # ---- Timeline ----
        # Load_middleware lets you know what _middleware_chain is.
        # it could be '_get_response' or some middleware instance (the instance has an internal attribute of '_get_Response')
        # Assuming it is a middleware instance, please continue to scroll down.
        response = self._middleware_chain(request)

        # Remove some seemingly unimportant code, that is, respond directly to the 'response' object.return response

    def load_middleware(self) :
        This method is called in the __init__ method when the application is instantiated at runServer.

        self._view_middleware = []
        self._template_response_middleware = []
        self._exception_middleware = []

        # 'convert_EXCEPtion_to_response' is written as a decorator.
        # This method completes the trapping of some exceptions to the response
        Django 404, 500, etc
        Now 'handler' points to the '_get_response' method
        handler = convert_exception_to_response(self._get_response)

        Get Settings middleware configuration
        for middleware_path in reversed(settings.MIDDLEWARE):
            # Dynamic import module
            middleware = import_string(middleware_path)
            try:
                # Note: When instantiated, 'handler' is passed as an attribute
                mw_instance = middleware(handler)  # instantiation
            except MiddlewareNotUsed as exc:
                # Some less important code has been deleted by me...# method of stuffing middleware implementation
            if hasattr(mw_instance, 'process_view'):
                self._view_middleware.insert(0, mw_instance.process_view)
            if hasattr(mw_instance, 'process_template_response'):
                self._template_response_middleware.append(mw_instance.process_template_response)
            if hasattr(mw_instance, 'process_exception'):
                self._exception_middleware.append(mw_instance.process_exception)

            Handler is reassigned to middleware instance (seems to be reassigned all the time)
            handler = convert_exception_to_response(mw_instance)

        This property may be either a '__get_response' method or a middleware instance
        self._middleware_chain = handler
Copy the code

The above, we learned that by implementing the framework wsgi run a service, the django. Core. Handlers. Wsgi. Py WSGIHandler instance Settings for the application.

When WSGIHandler is instantiated, the load_middleware method is executed, which loads Djangos middleware and sets the _MIDDLEWARE_chain property. (This attribute could be _get_Response or an instance of middleware that has a _get_Response attribute.)

The request is forwarded to the application Django, which is __call__ under WSGIHandler, where the route resolver is set up and _MIDDLEWARE_chain is called, returning a response object.

Now, what happens to _middleware_chain?

get

Since we set _MIDDLEware_chain to be middleware and an instance of a class, the question arises.

What method does an instance call in parentheses? The answer is the class’s __call__ method.

The __call__ method is defined in MiddlewareMixin under Django.utils.deprecation. (The subclasses that inherit it do not implement the __call__ method.)


# django.utils.deprecation.py

class MiddlewareMixin:
    def __init__(self, get_response=None) :
        # Remember 'get_response'?
        self.get_response = get_response
        super().__init__()

    def __call__(self, request) :
        The execution of '_MIDDLEware_chain' mentioned above is actually executed here. "" "
        response = None
        # start processing middleware methods, request comes in...
        if hasattr(self, 'process_request') :If the middleware method returns a Response object, it truncates subsequent operations.
            response = self.process_request(request)
        # Here's where it gets really interesting. Let's assume that the middleware method does not intercept and executes the 'get_response' method.
        This is where the logic of request processing comes in... Let's keep going down
        response = response or self.get_response(request)
        Continue with the middleware method
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response
Copy the code

The above mainly calls the middleware’s __call__ method, in which the middleware related processing methods are executed, continuing the anatomy.


# django. Core. Handlers. Base. Py of BaseHandler ` _get_response ` method

def _get_response(self, request) :
    "" Parses and invokes views, as well as view, exception, and template response middleware. This method is everything that happens in the request/response middleware. "" "
    response = None

    Import and get a parser object based on the Settings url node.
    if hasattr(request, 'urlconf'):
        urlconf = request.urlconf
        set_urlconf(urlconf)
        resolver = get_resolver(urlconf)
    else:
        resolver = get_resolver()

    Get the matching view in Djangos route resolver based on the route accessed
    resolver_match = resolver.resolve(request.path_info)
    callback, callback_args, callback_kwargs = resolver_match
    request.resolver_match = resolver_match

    # Execute middleware with 'process_view' method
    for middleware_method in self._view_middleware:
        response = middleware_method(request, callback, callback_args, callback_kwargs)
        if response:
            break

    If the response object is not intercepted, execute the view function
    if response is None:
        Ensure atomicity of views, where variables represent views
        wrapped_callback = self.make_view_atomic(callback)
        try:
            Django has two views, FBV and CBV
            # CBV calls the 'as_view' method, internally implementing the view function, which is then distributed to the class's 'dispatch' method and mapped to the specific method by reflection.
            This is essentially calling the view function.
            This step is actually executing the logic in your view.
            response = wrapped_callback(request, *callback_args, **callback_kwargs)
        except Exception as e:
            If the exception is caught here, execute the middleware with the 'process_exception' method
            response = self.process_exception_by_middleware(e, request)

    if response is None:
        You must return a response object..If the view middleware above returns a Response object that can be called
    elif hasattr(response, 'render') and callable(response.render):
        # execute middleware with 'process_template_response' method
        for middleware_method in self._template_response_middleware:
            response = middleware_method(request, response)

        try:
            response = response.render()
        except Exception as e:
            If an exception occurs, the middleware is caught here and executed with the 'process_exception' method
            response = self.process_exception_by_middleware(e, request)

    Respond to the response object.
    return response

Copy the code

At this point, through the above analysis, we know how the request gets into our view logic if it comes in.

conclusion

When our service runs, the setup application handler WSGIHandler instantiates the middleware operations loaded.

When the request comes in, it is forwarded to a __call__ method under WSGIHandler, which initializes the request and encapsulates the request information into the WSGIRequest object.

Then I go down to the get_response method which basically sets the configuration module path of the route, to the _MIDDLEware_chain method, It is either a _get_Response object or an instance of middleware that has a get_Response attribute pointing to the _get_Response method. Here we assume it is a middleware instance, calling the instance’s __call__ method (which exists under MiddlewareMixin). Process_request and process_response middleware are executed under this method, and _get_response is executed between them. This method parses the route and calls view methods and some middleware methods.

Under the _get_response method, the instance of the route parser is obtained. The route parser matches the request information to the view and executes the view method to obtain the response result (it will be called if the middleware sets relevant methods).