Django 0.95 Internals: Custom Request/Response Hooks via Middleware
Django is quickly becoming the 'batteries-included' alternative to the Ruby on Rails hype. One of its most elegant architectural features is the Middleware system. In 2006, with Django 0.95, we have a robust way to plug into the core request/response cycle without cluttering our views or URLconfs.
What is Middleware?
Middleware is a light, low-level 'plugin' system for globally altering Django’s input or output. Each middleware component is responsible for doing some specific function. For example, AuthenticationMiddleware associates users with requests using sessions.
The Middleware Methods
A middleware class can define one or more of the following methods:
process_request(self, request)process_view(self, request, view_func, view_args, view_kwargs)process_response(self, request, response)process_exception(self, request, exception)
Example: A Simple Execution Timer
Let's write a middleware that adds a header to the response showing how long the request took to process.
import time
class StatsMiddleware(object):
def process_request(self, request):
request.start_time = time.time()
def process_response(self, request, response):
if hasattr(request, 'start_time'):
duration = time.time() - request.start_time
response['X-Process-Time'] = str(duration)
return response
To enable this, you just add the full Python path to your MIDDLEWARE_CLASSES setting in settings.py:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'myapp.middleware.StatsMiddleware',
)
Order Matters!
The order in MIDDLEWARE_CLASSES is crucial. During the request phase, Django applies middleware from top to bottom. During the response phase, it applies them from bottom to top (like an onion). This means if your middleware needs to access the request.user object, it must be listed after AuthenticationMiddleware.
Global Exception Handling
You can also use middleware to catch errors and send alerts. This is how many early Django developers integrated with services like Jabber or emailed themselves tracebacks before tools like Sentry existed.
class ErrorLoggingMiddleware(object):
def process_exception(self, request, exception):
print "Something went wrong at %s: %s" % (request.path, exception)
# You could send an email or log to a file here
return None # Let Django's default exception handling continue
Aunimeda develops websites and web applications for businesses - corporate sites, e-commerce, portals, and custom platforms.
Contact us to discuss your web project. See also: Web Development, E-commerce Development