Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.
Each middleware is responsible for performing some specific function. For example, Django includes a middleware component, AuthenticationMiddleware, that associates users with requests using sessions.
After server receives user’s request, before calling the respecting view, Django applies the middleware in top down order as defined in the settings.py MIDDLEWARE list.
To better understand the concept, Django documentation gives a nice analogy on onions. Each middleware can be thought as the outer layers that wraps the core i.e view. Each layer passes request to its inner layer, which creates the Request flow from outer layers to the core.
Basic steps to create a custom middleware.
- Create a folder named “middlewares” in a Django app.
- Inside the folder create a file named “__init__.py”
- Logic for middleware goes into the file.
- Finally add the middleware to MIDDLEWARE list at “project_name/settings.py”.
Now, lets focus on step 3, i.e. Code inside the middleware file. To better understand the concept let’s take a real world scenario and design a middleware for it.
Each user request contains a HTTP header “LANG”. The header field contains the name of the language stored in the database. For each request we have to check whether the language exists it database or not. It not, respective error message should be returned. The view then returns the content in requested language. Incase the header field doesn’t exist respective error message is sent to the user. Since we are using REST API the responses will be in JSON format.
We will be using django’s 1.10-style middleware.
The bare structure of a middleware looks like this.
All the logic happens in “process_request” function. Initially, existence of the slug is checked. It it doesn’t exist in HTTP header, error is thrown. Then, The language is checked in the database. If exists, then ok. Else, error is thrown.
A separate function “respond” is called every time with a “message” parameter when a response is to be sent. The content type is set as “application/json” since response is in json.
None response is returned in case everything is fine.