Introspection through
the Django request/response
lifecycle



David Elias - 28/01/2014

/me


  • Web developer since 2002 with PHP
  • Started using Django v0.95 in 2006

WSGI


  • WSGI application are python callable objects (function or classes with a __call__ method)
  • Two arguments are passed, a WSGI environment and a function that starts the response
  • The  application has to start the response using the function provided
    and return a 
    iterable where each yielded item means writing and flushing

 

WSGI

Simple example


def hello_world(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ["Hola, Buenas noches!"]

Django


  • Each django project has  a wsgi module
  • This module will be used by wsgi servers:
    • gunicorn
    • uWSGI
    • mod_wsgi

WSGI


module used by default for all Django projects


django/conf/project_template/project_name/wsgi.py

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE",
    "{{ project_name }}.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

WSGI


  • Public api of Django's WSGI support
  • Avoid making WSGIHandler public api
    in case the internal implementation changes

 django/core/wsgi.py

from django.core.handlers.wsgi import WSGIHandler

def get_wsgi_application():
    return WSGIHandler()

WSGI

Django's handler

 django/core/handlers/wsgi.py L206
response = self.get_response(request)
...
status = '%s %s' % (response.status_code, response.reason_phrase)
response_headers = [(str(k), str(v)) for k, v in response.items()]
...
start_response(force_str(status), response_headers)
return response

Middleware


Each middleware defines one or more
of the following methods

Request phase, before calling the view two methods are available.
The middleware is applied in the order it’s defined in MIDDLEWARE_CLASSES, top-down.

  • process_request
  • process_view

Middleware

process_request

  • if process_request returns a valid response
    the middleware processing is interrupted
  • during process_request a new urlconf can be defined
    to override the URLCONF setting
class NachosMiddleware(object):    def process_request(self, request):        request.urlconf = 'nachos.core.urls'

Middleware

process_view

  • The view is resolved based on the urlconf and request path
  • process_view is called with the callable view (function or class) along with the args and kwargs

class NachosMiddleware(object):    def process_view(self, request, callback, callback_args, callback_kwargs):        pass

  • the middleware is interrupted if a valid response is returned
  • then the view is executed and a valid response must be returned

Middleware


Response phase, after calling the view three methods are available.
The middleware is applied in reverse order, from the bottom up.

  • process_exception
  • process_template_response
  • process_response

Middleware

process_exception

  • If the raises an exception it will be processed by process_exception
  • Again if a valid response is returned it will be used and the process interrupted

class NachosMiddleware(object):    def process_exception(self, request, e):        pass

Middleware

process_template_response

  • if the response returned for all the previous middleware and view defines a render method it will processed now
  • a response with a render indicates that is TemplateResponse object, useful to excute post render callbacks

Middleware

process_response

the process_response is always called and can be
used to alter the returned response in
previews middleware or to return a completely new one.

class NachosMiddleware(object):    def process_response(self, response):        return response



Thank you!


github.com/davidelias
Made with Slides.com