Understanding Middleware

by Marty Alchin on November 19, 2007

While it’s not news, I believe the fact that Django supports custom middleware deserves a good bit of attention. Unfortunately, I’m starting this post too late to do it real justice, but I’ll cover the protocol in a basic overview. The main point I want to cover is what types of things can be done with middleware. I won’t pretend to list everything that can be done, but just a few ideas that should give you somewhere to run with it.

Middleware don’t have to subclass anything, they just have to implement one of four methods. They could include any other methods or variables, but that’s only necessary if your middleware has particular need for it. The four methods are detailed below, in the order they’re processed, along with what types of things each can perform.

process_request(self, request)

When a request first comes in, this method runs any code that doesn’t need to care about which view will be run. This is often used for two purposes:

Since process_request() can return an HttpResponse, it can short-cirtuit the entire process, return a response before any view is even run. This makes it great for global bans or redirects.

process_view(self, request, view, args, kwargs)

This gets called after the URL has been resolved to a view function, but before the view is called. This allows code to be executed according to which view will be called, and/or which arguments will be passed to that view.

This isn’t useful in many cases, but one particularly interesting use is a custom logger. Your code could simply log which view will be called and with which arguments, for the sake of a more project-oriented record of events. Or, perhaps more interestingly still, it could execute different for a particular view.

For instance, process_view() could be used along with generic relations to determine exactly which objects are being loaded, without regard to the URL being used for it. It could basically check if the view is object_detail, and store the id passed to the view.

process_response(self, request, response)

After the view has run, it returns an HttpResponse, which can be viewed here, along with the original request. This allows some powerful processing, such as compressing the output, manipulating bits of the response’s text, or signing cookies.

process_exception(self, request, exception)

Also not used very often, this has some intersting untapped potential. It runs in the event that the view or any middleware threw any errors. The method gets the exception and can handle it however it likes. One potential use is to automatically file tickets in Trac in production sites, and append new cases where the same error occurs. This could make it much easier to locate and fix bugs in production, without requiring people to send an error report manually.