In a recent interview, I was asked by an interviewer how the user in request.user was obtained. I didn’t answer this question at that time, which was very embarrassing.

To answer the question of why the requested user can be obtained directly from request.user, you should first look at the process by which the request is processed and how the response is returned. Today, I’ll summarize how Django goes from request to response.

WSGI

When a client sends a request, the first request is actually handled by a Web server, such as Nginx or Apache. WSGI is used to connect the Web server to the Web framework (Django). WSGI is divided into two parts: the server side and the application side. To process a WSGI response, the server executes the application and provides a callback function to the application, which processes the request and returns the response to the server using the provided callback. In essence, I see WSGI as a liaison between the Web server and django applications.

The data flow

When a user sends a request to your application, a WSGI handler is initialized, which does the following:

  1. Import settings.py and Django exception classes
  2. Use the load_middleware method to load MIDDLEWARE_CLASSES in settings.py or MIDDLEWARES tuples.
  3. Create four lists (_request_middleware,_view_middleware, _response_middleware, and _EXCEPtion_middleware), It contains methods for handling request, View, Response, and exception, respectively.
  4. WSGI Handler will instantiate a django. HTTP. HTTPRequest object’s subclasses, django. Core. Handlers. WSGI. WSGIRequest.
  5. Loop through the methods that process requests (the _request_middleware list) and call them in order
  6. Parse the requested URL
  7. Loop through each method that processes a view (_view_middleware list)
  8. If it finds one, it calls the view function
  9. Methods to handle any exceptions (_exception_middleware list)
  10. Loop through each method that processes a response (the _response_middleware list), (from inside out, in reverse order of requesting middleware)
  11. Finally, you get a response and invoke the callback function provided by the Web Server

The middleware

Middleware is used in many of Django’s key functions: for example, the CSRF intermediate key is used to prevent cross-site request forgery attacks. They are also used to process session data, and authentication and authorization are also done by middleware. We can also write our own middleware to tune or (short-circuit) the flow of data through the application.

Djangos middleware contains at least one of four methods: process_request, process_response, process_view, and process_exception. These methods are collected by the WSGI handler and called in order.

process_request

We can let’s look at the django. Contrib. Auth. Middleware. AuthenticationMiddleware:

def get_user(request):
    if not hasattr(request, '_cached_user'):
        request._cached_user = auth.get_user(request)
    return request._cached_user

class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        assert hasattr(request, 'session'), (
              "The Django authentication middleware requires session middleware "
              "to be installed. Edit your MIDDLEWARE%s setting to insert "
              "'django.contrib.sessions.middleware.SessionMiddleware' before "
              "'django.contrib.auth.middleware.AuthenticationMiddleware'."
        ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
        request.user = SimpleLazyObject(lambda: get_user(request))
Copy the code

Here we can see that the request.user property is generated in AuthenticationMiddleware. We’ll talk about that later.

As you can see here, the middleware only has process_request, indicating that it only handles the flow of data into and out of a Django application in the request step. The middleware first verifies that the session middleware is in use and then sets the user by calling the get_user function. When the WSGI handler iterates through the list of process_request methods, it will build the request object that will eventually be passed to the view function, enabling you to reference Request.user. Some middleware does not have the process_request method and will be skipped at this stage.

Process_request should return None or An HTTPResponse object. When None is returned, the WSGI handler continues loading the methods in process_Request, but the latter case short-circuits the processing and enters the process_response loop.

Parsing the url

When all process_request has been called, we get a request object that will be passed to the view function. Before this event occurs, Django must parse the URL and decide which view function to call. The process is as simple as using regular matching. Settings. py has a ROOT_URLCONF key to specify the root url.py, which contains all of your app’s urls.py files. If no match is successful, it will throw an exception. Django core. Urlresolvers. Resolver404, this is your django. HTTP. HTTP404 subclass.

process_view

At this point, the WSGI handler knows which view function to call and which parameters to pass. It calls the method in the middleware list again, this time the _view_middleware list. All Django middleware process_view methods will be declared as follows:

process_view(request, view_function, view_args, view_kwargs)

As with process_REQUEST, the process_view function must return None or an HTTPResponse object, allowing the WSGI handler to continue processing the view or ‘short-circuit’ the process and return a response. There is a process_view method in CSRF Middleware. The process_view method will return None and the view function will continue to execute when CSRF cookies appear. If this is not the case, the request will be rejected and the process will be ‘short-circuited’, generating an error message.

Go to the view function

A view function needs to satisfy three conditions:

  • It must be callable. This can be a function-based View or a class-based View that inherits from the View and makes it callable using the as_view() method. These method calls depend on HTTP verb(GET, POST, etc).
  • You must accept an HTTPRequest object as the first positional argument. This HTTPRequest object is the result of all process_REQUEST and process_VIEW middleware methods.
  • You must either return an HTTPResponse object or throw an exception. This response object is used to start the PROCESS_view loop of the WSGI handler.

process_exception

If the view function throws an exception, the Handler loops through the _Exception_Middleware list, executing the methods in reverse order, from the last middleware listed in settings.py to the first. If an exception is thrown, the processing will be short-circuited and the other process_exceptions will not be executed. Normally we rely on exception handlers provided by Djnago’s BaseHandler, but we can also use custom exception handling middleware.

process_response

At this stage, we get an HTTPResponse object, either returned by process_VIEW or by the view function. Now we’ll loop through the response middleware. This is the middleware’s last chance to tweak the data. The order of execution is from the inside out. Take cache Middleware’s process_response: it depends on different states in your app (whether the cache is on or off, whether a data stream is being processed) to decide whether to cache your response.

Pay attention to

The difference between Django 1.10 and previous versions: In MIDDLEWARE_CLASSES, even if one middleware “short-circuits” the execution, all middleware calls their process_response method. In the new MIDDLEWARES version, the process_response method is called only by this middleware and any middleware that executes before it.

conclusion

That’s the basic process of handling a request. Django’s WSGI Handler creates a return value from An HTTPResponse and calls a callback function to pass the data to the Web Server, which then returns it to the user.

Here are two key points:

  • We now know how the view function matches the URL parser and what is calling it (WSGI Handler)
  • There are four key places where you can hook into the request/response cycle: process_request, process_response, process_VIEW, and process_exception. The request middleware executes from the outside in, finally arrives at the view function, and then returns from the inside out via the response middleware.

The resources

  • Django Middlewares and the Request/Response Cycle
  • How Django processes a request

— — — — — — — — — — — — — — — — — –, concern WeChat public number: gen yu front (KnownsecFED), code for more high quality dry!