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).