How to create custom middleware in Django?
The TLDR answer:
- Create a file
custom_middleware.pyfile in the same folder as where Django
settings.pyfile is present
- Add the following code in
- Add the custom middleware in your
That's it. You created a custom middleware that will print whenever a request is sent to your application and also when the response is sent back
The Detail answer:
Django Middleware is a regular Python class that hooks into Django's request/response cycle. Generally, Django middleware is a plug-and-play system that can be used to modify a request before the Django view processes it or alter the response which is sent back from Django view to the client.
Django middleware classes are called when the request is sent from the client and the next time when the response is sent to the client. By default, Django gives certain middleware classes out of the box. Most of them are security-related, you can find this middleware in the
Django middleware classes are executed layer by layer, when a request comes then it executes Top to Bottom, layer by layer middleware classes, once the request is processed by the view and response is returned, then it would execute every middleware class opposite order, i.e. from bottom to top. The following image depicts the request-response cycle and how Django middleware is executed.
Django middleware makes use of the simple python class concept. Once the middleware class is instantiated then for every request it would execute all the code written inside the
get_response method call acts like the
yield the keyword which would then pass the control to the next middleware or the Django view, and once the response is returned, then it would resume the execution from the point where
get_response was left.
Now let us create a custom middleware, in the file
custom_middleware.py add the following code.
Once you have written the middleware code, you would have to plug it in to your Django request/response flow. You need to add the entry to
MIDDLEWAREsection. Please remember to add the middleware at an appropriate position, since the evaluation of middleware is position dependent.
Let's look into how this code actually works
- When you start your Django server, then Django will go and pick up all the middleware you have mentioned in the
settings.pyfile and instantiate it.
CustomMiddlewaregets instantiated and the
__init__constructor is called.
- Whenever a request would come to Django then, Django would then start calling the middleware one by one from top-down list mentioned in the
__call__the method gets called, for the first middleware and subsequent middleware which are built-in or custom-built are called.
- Once the request reaches
__call__the method is called which executes the following code.
print("custom middleware before next middleware/view")would get executed whenever this middleware is called
- Once the program reaches
response = self.get_response(request)then this would send the request to the next middleware or the Django view.
- Once the request reaches the view and it would execute and process the request to create a relevant response. The response is then returned, and it would be saved in
- The code now starts to execute the next line i.e.
print("custom middleware after response or previous middleware")
- At this point we have access to the response object, if we want to tweak something in the response object then we can do it now.
- Finally, we return the response to the previous middleware or the client.
When do we use custom middleware?
Custom middleware should be used when you want to implement certain code for every request or response or both. Most of the middleware which comes out of the box is sufficient for you to learn Django, I would recommend writing Django Custom middleware only when you have unique requirements in production since it would mean additional overhead to the request-response cycle which certain times can put negative effect.
I have written custom middleware in Django for the following use cases.
- Multi-tenant architecture using Django where I wanted to set tenant ID for every request
- Add logging or monitoring to endpoints which you have built. For example, if I wanted to ignore certain endpoints from getting tracked by NewRelic in Django, the best way to do so is using middleware.