Get Django Updates

View method middleware

In most circumstances, data in requests & responses is added, removed or updated in a piecemeal fashion in view methods. However, sometimes it's convenient to apply these changes on all requests and responses.

For example, if you want to access certain data on all view methods, it's easier to use a middleware class to make this data accessible across all requests. Just as if you want to enforce a security check on all responses, it's easier to do so globally with a middleware class.

Since middleware is a rather abstract concept, before I describe the structure of a Django middleware class, I'll walk you through the various built-in Django middleware classes so you can get a firmer understanding of where middleware is good design choice.

Built-in middleware classes

Django comes equipped with a series of middleware classes, some of which are enabled by default on all Django projects. If you open a Django project's settings.py file you'll notice the MIDDLEWARE variable whose default contents are shown in listing 2-25.

Listing 2-25 Default Django middleware classes in MIDDLEWARE

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

As you can see in listing 2-25, Django projects in their out-of-the-box state come enabled with seven middleware classes, so all requests and responses are set to run through these seven classes. If you plan to leverage Django's main features, I advise you not to remove any of these default middleware classes. However, you can leave the MIDDLEWARE variable empty if you wish, just be aware doing so may break certain Django functionalities.

To give you a better understanding of what the Django middleware classes in listing 2-25 do and help you make a more informed decision to disable them or not, table 2-6 describes the functionality for each of these middleware classes.

Table 2-6 Django default middleware classes and functionality

Middleware classFunctionality
django.middleware.security.SecurityMiddleware Provides security enhancements, such as:
SSL redirects based on the SECURE_SSL_REDIRECT and SECURE_SSL_HOST settings.
Strict transport security through a variety of settings.
django.contrib.sessions.middleware.SessionMiddleware Enables session support.
django.middleware.common.CommonMiddleware Provides a common set of features, such as:
Forbidding access to user agents in the DISALLOWED_USER_AGENTS setting, which can be a list of compiled regular expression objects.
Performing url rewriting based on the APPEND_SLASH and PREPEND_WWW settings in order to normalize urls.
Setting the HTTP Content-Length header for non-streaming responses.
django.middleware.csrf.CsrfViewMiddleware Adds protection against Cross Site Request Forgeries by adding hidden form fields to POST forms and checking requests for the correct value.
django.contrib.auth.middleware.AuthenticationMiddleware Adds the user attribute, representing the currently-logged-in user, to every incoming HttpRequest object. NOTE: This middleware class depends on functionality from the middleware django.contrib.sessions.middleware.SessionMiddleware and must appear after it.
django.contrib.messages.middleware.MessageMiddleware Enables cookie-based and session-based message support. NOTE: This middleware class depends on functionality from the middleware django.contrib.sessions.middleware.SessionMiddleware and must appear after it.
django.middleware.clickjacking.XFrameOptionsMiddleware Provides clickjacking protection via the X-Frame-Options header. For more details on what is clickjacking see: http://en.wikipedia.org/wiki/Clickjacking.

As you can see in table 2-6, although the purpose of the various default middleware classes varies considerably, their functionality applies to features that need to be applied across all requests or responses in a project.

Another important factor of the middleware classes in table 2-6 is that some are dependent on others. For example, the AuthenticationMiddleware class is designed on the assumption it will have access to functionality provided by the SessionMiddleware class. Such dependencies are important because it makes the middleware class definition order relevant (i.e. certain middleware classes need to be defined before others in MIDDLEWARE) a topic I'll elaborate on more in the next section.

In addition to the default middleware classes presented in table 2-6, Django also offers other middleware classes. Table 2-6 illustrates the remaining set of Django middleware classes you can leverage in your projects, which can be helpful so you don't have to write middleware classes from scratch.

Table 2-7 Other Django middleware classes and functionality

Middleware classFunctionality
django.middleware.cache.UpdateCacheMiddleware Response-phase cache middleware that updates the cache if the response is cacheable.NOTE: UpdateCacheMiddleware must be the first piece of middleware in MIDDLEWARE so that it'll get called last during the response phase.
django.middleware.cache.FetchFromCacheMiddleware Request-phase cache middleware that fetches a page from the cache. NOTE: FetchFromCacheMiddleware must be the last piece of middleware in MIDDLEWARE so that it'll get called last during the request phase.
django.middleware.common.BrokenLinkEmailsMiddleware Sends broken link notification emails to MANAGERS.
django.middleware.ExceptionMiddleware Django uses this middleware regardless of whether or not you include it in MIDDLEWARE, however, you may want to subclass if your own middleware needs to transform the exceptions it handles into the appropriate responses.
django.middleware.gzip.GZipMiddleware Compresses content for browsers that understand GZip compression. NOTE: GZipMiddleware should be placed before any other middleware that need to read or write the response body so that compression happens afterward. Compression is only done by this middleware if the request party sends gzip on the HTTP Accept-Encoding header and if content is larger than 200 bytes and the response hasn't set the HTTP Content-Encoding header.
django.middleware.http.ConditionalGetMiddleware Handles conditional GET operations. If the response doesn't have an HTTP ETag header, one is added. If the response has an ETag or Last-Modified header, and the request has If-None-Match or If-Modified-Since, the response is replaced by an HttpNotModified.
django.middleware.locale.LocaleMiddleware Parses a request and decides what translation object to install in the current thread context. This allows pages to be dynamically translated to the language the user desires.
django.contrib.sites.middleware.CurrentSiteMiddleware Adds the site attribute representing the current site to every incoming HttpRequest object.
django.contrib.auth.middleware.PersistentRemoteUserMiddleware Adds REMOTE_USER -- available in request.META -- via an external source (e.g. web server) for the purpose of Django authentication.
django.contrib.auth.middleware.RemoteUserMiddleware Allows web-server-provided authentication.If request.user is not authenticated, this middleware attempts to authenticate the username passed in the REMOTE_USER request header. If authentication is successful, the user is automatically logged in to persist the user in the session.
django.contrib.flatpages.middleware.FlatpageFallbackMiddleware Each time a Django application raises a 404 error, this middleware checks the flatpages database for the requested url as a last resort.
django.contrib.redirects.middleware.RedirectFallbackMiddleware Each time a Django application raises a 404 error, this middleware checks the redirects database for the requested url as a last resort.

Now that you know about Django's built-in middleware classes and what it's they're used for, lets take a look at the structure of middleware classes and their execution process.

Middleware structure & execution process

A Django middleware class has two required methods and three optional methods that execute at different points of the view request/response life-cycle. Listing 2-26 illustrates a sample middleware class with its various parts.

Listing 2-26. Django middleware class structure

class CoffeehouseMiddleware(object):

    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization on start-up

    def __call__(self, request):
        # Logic executed on a request before the view (and other middleware) is called.

        # get_response call triggers next phase
        response = self.get_response(request)

        # Logic executed on response after the view is called.

        # Return response to finish middleware sequence
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        # Logic executed before a call to view
        # Gives access to the view itself & arguments

    def process_exception(self,request, exception):
        # Logic executed if an exception/error occurs in the view

    def process_template_response(self,request, response):
        # Logic executed after the view is called, 
        # ONLY IF view response is TemplateResponse, see listing 2-21 

In order for view methods to execute the Django middleware class in listing 2-26, middleware classes must be added to the MIDDLEWARE variable in settings.py. So for example, if the CoffeehouseMiddleware class in listing 2-26 is stored in a file/module named middleware.py under the coffeehouse/utils/ project folders, you would add the coffeehouse.utils.middleware.CoffeeMiddleware statement to the list of MIDDLEWARE values in settings.py.

Next, let's describe the two required methods in all Django middleware class show In listing 2-26:

This is the core logic behind every Django middleware class performed by these two required methods. Now let's take a look at the three optional middleware class methods presented in listing 2-26: