The request/response cycle

- A djangonautic journey

Timothy McCurrach

The scope of this talk

Just the django layer

Just the WSGI route (not ASGI)

What is WSGI?

Web Standard Gateway Interface

A specification

PEP 3333

What does a WSGI application look like?

def wsgi_application(environ, start_response):  #0 fragment fragHighlight
    response = b"Hello world!"                  #1 fragment fragHighlight
    response_headers = [                        #1 fragment fragHighlight
        ("Content-Type", "text/plain"),         #1 fragment fragHighlight
    ]                                           #1 fragment fragHighlight
    status="200 OK"                             #1 fragment fragHighlight
    start_response(status, response_headers)    #2 fragment fragHighlight
    return [response]	                        #3 fragment fragHighlight
    					

How does Django implement WSGI?

project
 ├── project
 │    ├── __init__.py
 │    ├── asgi.py
 │    ├── settings.py
 │    ├── urls.py
 │    ├── wsgi.py
 ├── manage.py
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')

application = get_wsgi_application() #4 fragment fragHighlight

How does Django implement WSGI?

project
 ├── project
 │    ├── __init__.py
 │    ├── asgi.py
 │    ├── settings.py
 │    ├── urls.py
 │    ├── wsgi.py
 ├── manage.py
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')

application = get_wsgi_application()
def get_wsgi_application():
    django.setup(set_prefix=False)
    return WSGIHandler()	#2 fragment fragHighlight

How can we make this better?

class WSGIHandler:

    def __call__(self, environ, start_response): #0 fragment fragHighlight
        response = b"Hello world!" 			     #1 fragment fragHighlight		
        response_headers = [					 #1 fragment fragHighlight
            ("Content-Type", "text/plain"),		 #1 fragment fragHighlight
        ]										 #1 fragment fragHighlight
        status="200 OK"							 #1 fragment fragHighlight
        start_response(status, response_headers) #1 fragment fragHighlight
        return [response]						 #1 fragment fragHighlight
        				

How can we make this better?

class WSGIHandler:

    def __call__(self, environ, start_response):
        response = b"Hello world!"
        response_headers = [
            ("Content-Type", "text/plain"),
        ]
        status="200 OK"
        start_response(status, response_headers)
        return [response]
    					

How can we make this better?

from django.conf import settings #0 fragment expand diffPlus
from django.utils.module_loading import import_string #0 fragment expand diffPlus
#0 fragment expand
class WSGIHandler:

    def __call__(self, environ, start_response):
        view = import_string(settings.THE_VIEW) #0 fragment expand diffPlus
        response = view() #0 fragment expand diffPlus
        response = b"Hello world!"  #diffMinus
        response_headers = [
            ("Content-Type", "text/plain"),
        ]
        status="200 OK"  
        start_response(status, response_headers)
        return [response]
    					

What next?


class WSGIHandler:

    def __call__(self, environ, start_response):
        view = import_string(settings.THE_VIEW)
        response = view() #1 fragment fragHighlight then-leave
        response = view(environ) #2 fragment fragHighlight arrive
        response_headers = [
            ("Content-Type", "text/plain"),
        ]
        status="200 OK"  
        start_response(status, response_headers)
        return [response]
    					

What next?


class WSGIHandler:

    def __call__(self, environ, start_response):
        view = import_string(settings.THE_VIEW)
        request = WSGIRequest(environ)              #1 fragment expand diffPlus
        response = view() #1 fragment fragDiffMinus
        response = view(request) #1 fragment expand diffPlus
        response_headers = [
            ("Content-Type", "text/plain"),
        ]
        status="200 OK"  
        start_response(status, response_headers)
        return [response]
    					

WSGI Request

class WSGIRequest:

	def __init__(self, environ):
		self.method = environ['REQUEST_METHOD'].upper()
        self.path_info = get_path_info(environ) or '/'
        self.META = environ
    					
    @cached_property
    def GET(self):
        raw_query_string = self.environ
        	.get('QUERY_STRING', '')
        	.encode('iso-8859-1')

        return QueryDict(
        	raw_query_string,
        	encoding=settings.DEFAULT_CHARSET
        )
    @cached_property
    def COOKIES(self):
        raw_cookie = get_str_from_wsgi(
            self.environ,
            'HTTP_COOKIE',
            ''
        )
        return parse_cookie(raw_cookie)
    @property
    def FILES(self):
        if not hasattr(self, '_files'):
            self._load_post_and_files()
        return self._files
    @cached_property
    def headers(self):
        return HttpHeaders(self.META)
    def _get_post(self):
        if not hasattr(self, '_post'):
            self._load_post_and_files()
        return self._post

    def _set_post(self, post):
        self._post = post

    POST = property(_get_post, _set_post)
class WSGIHandler:
 #7 fragment expand
    request_class = WSGIRequest                     #7 fragment expand diffPlus
 #7 fragment expand
    def __call__(self, environ, start_response):
        view = import_string(settings.THE_VIEW)
        request = WSGIRequest(environ)              #7 fragment diffPlus leave
        request = self.request_class(environ)       #7 fragment arrive diffPlus
        response = view(request)                    # diffPlus
        response = view()                           # diffMinus
        response_headers = [
            ("Content-Type", "text/plain"),
        ]
        status="200 OK"
        start_response(status, response_headers)
        return [response]
    					

A custom request class

from django.core.handlers.wsgi import WSGIHandler, WSGIRequest


class CustomWSGIRequest(WSGIRequest):

	def some_cool_method(self):
		return do_something_cool()


class CustomWSGIHandler(WSGIHandler):
	request_class = CustomWSGIRequest
					

How can I raise a 403?

class WSGIHandler:

    request_class = WSGIRequest

    def __call__(self, environ, start_response):
        view = import_string(settings.THE_VIEW)
        request = self.request_class(environ)
        response = view(request) #4 fragment fragHighlight
        response_headers = [    #3 fragment fragHighlight
            ("Content-Type", "text/plain"),    #3 fragment fragHighlight
        ]    #3 fragment fragHighlight
        status="200 OK" #2 fragment fragHighlight
        start_response(status, response_headers)
        return [response] #5 fragment
    					

HttpResponse

class HttpResponse:
0000000000000000000000000000000000000000000000000000 #invisible
    def __init__(self, content=b''):    #8 fragment leave 
    def __init__(self, content=b'', status=None) #8 fragment arrive
    	self.content = content
    	self.status_code = status #8 fragment expand
    @property
    def content(self):
        return b''.join(self._container) #5 fragment

    @content.setter                                    #3 fragment fragHighlight
    def content(self, value):                          #3 fragment fragHighlight
        content = bytes(value.encode(self.charset))    #3 fragment fragHighlight
        self._container = [content]                    #3 fragment fragHighlight

    def __iter__(self):                                #4 fragment fragHighlight
        return iter(self._container)                   #4 fragment fragHighlight
    @property
    def reason_phrase(self):
        return responses.get(
        	self.status_code, 
        	'Unknown Status Code'
        )
	
    def __setitem__(self, header, value):
        self.headers[header] = value

    def __delitem__(self, header):
        del self.headers[header]

    def __getitem__(self, header):
        return self.headers[header]

    def has_header(self, header):
        return header in self.headers

    __contains__ = has_header

    def items(self):
        return self.headers.items()
class WSGIHandler:

    request_class = WSGIRequest

    def __call__(self, environ, start_response):
        view = import_string(settings.THE_VIEW)
        request = self.request_class(environ)
        response = view(request)
        response_headers = [                         #13 fragment fragDiffMinus
            ("Content-Type", "text/plain"),          #13 fragment fragDiffMinus
        ]                   						 #13 fragment fragDiffMinus
        response_headers = [                         #13 fragment expand diffPlus
            *response.items(),                       #13 fragment expand diffPlus
            *(                                       #14 fragment expand diffPlus
                ("Set-Cookie", c.output(header=""))  #14 fragment expand diffPlus
                for c in response.cookies.values()   #14 fragment expand diffPlus
             ), 									 #14 fragment expand diffPlus
        ]  									         #13 fragment expand diffPlus
        status="200 OK" 							 #7 fragment fragDiffMinus
        status = '%d %s' % ( 					     #10 fragment expand diffPlus
            response.status_code, 					 #10 fragment expand diffPlus
            response.reason_phrase 					 #10 fragment expand diffPlus
        ) 							                 #10 fragment expand diffPlus
        start_response(status, response_headers)
        return [response]                            #1 fragment fragDiffMinus
        return [response.content]                    #1 fragment appear diffPlus then-leave
        return response 							 #2 fragment appear diffPlus
    					

Let's add some signals...


class WSGIHandler:
    request_class = WSGIRequest

    def __call__(self, environ, start_response):
    	signals.request_started.send(sender=self.__class__, environ=environ) #2 fragment expand diffPlus
        view = import_string(settings.THE_VIEW)
        request = self.request_class(environ)
        response = view(request)

        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        return response
			

WSGI Specification

If the iterable returned by the application has a close() method, the server or gateway must call that method upon completion of the current request.

Let's add some signals...

class HttpResponse:
00000000000000000000000000000000000000000000000000000000000000000 #invisible
    def __init__(self, content=b'', status=None)
    	self.content = content
    	self.status_code = status

    def close(self):  #1 fragment expand diffPlus
		self.closed = True #1 fragment expand diffPlus
        signals.request_finished.send(sender=self._handler_class) #1 fragment expand diffPlus

Let's add some signals...

class HttpResponse:
00000000000000000000000000000000000000000000000000000000000000000 #invisible
    def __init__(self, content=b'', status=None)
    	self.content = content
    	self.status_code = status

    def close(self): #diffPlus
		self.closed = True #diffPlus
        signals.request_finished.send(sender=self._handler_class) #1 fragment fragHighlight diffPlus

Let's add some signals...

class WSGIHandler:
    request_class = WSGIRequest

    def __call__(self, environ, start_response):
    	signals.request_started.send(sender=self.__class__, environ=environ) # diffPlus
        view = import_string(settings.THE_VIEW)
        request = self.request_class(environ)
        response = view(request)
        response._handler_class = self.__class__ #1 fragment expand diffPlus

        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        return response
			
class WSGIHandler:
    request_class = WSGIRequest

    def __call__(self, environ, start_response):
    	signals.request_started.send(sender=self.__class__, environ=environ) 
        view = import_string(settings.THE_VIEW) #1 fragment fragDiffMinus
        request = self.request_class(environ) 
        response = view(request) #1 fragment fragDiffMinus
        response = self.get_response(request) #2 fragment expand diffPlus

        response._handler_class = self.__class__ 

        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        return response

    def get_response(self, request): #2 fragment expand diffPlus
        view = import_string(settings.THE_VIEW) #2 fragment expand diffPlus
        response = view(request) #2 fragment expand diffPlus
        return response   #2 fragment expand diffPlus

			
class WSGIHandler:
    request_class = WSGIRequest #1 fragment collapse
 #1 fragment collapse
    def __call__(self, environ, start_response): #1 fragment collapse
    	signals.request_started.send(sender=self.__class__, environ=environ)  #1 fragment collapse
        request = self.request_class(environ)  #1 fragment collapse
        response = self.get_response(request) #1 fragment collapse
        response._handler_class = self.__class__  #1 fragment collapse
 #1 fragment collapse
        status = '%d %s' % (response.status_code, response.reason_phrase) #1 fragment collapse
        response_headers = [ #1 fragment collapse
            *response.items(), #1 fragment collapse
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()), #1 fragment collapse
        ] #1 fragment collapse
        start_response(status, response_headers) #1 fragment collapse
        return response #1 fragment collapse
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000 #invisible
    def get_response(self, request):
        view = import_string(settings.THE_VIEW)
        response = view(request)
        return response
			

An introduction to Middleware

			middleware_1(middleware_2(middleware_3(view)))
		
class ExampleMiddleware:

	def __init__(self, get_response)
		self.get_response 

    def __call__(self, request): #8 fragment

    	do_some_useful_stuff(request) #4 fragment fragHighlight
    
    	response = self.get_response(request) #5 fragment fragHighlight
    
    	new_response = more_stuff(response, request) #6 fragment fragHighlight
    
    	return new_response #7 fragment fragHighlight
			
Middleware 1 Middleware 2 Middleware 3 Middleware 3 Middleware 2 Middleware 1 View

Time for some middleware...

class WSGIHandler:

    def get_response(self, request):
        view = import_string(settings.THE_VIEW)				   
       	response = view(request)                               #1 fragment fragDiffMinus
        handler = view 										   #1 fragment expand diffPlus 
        for middleware_path in reversed(settings.MIDDLEWARE):  #1 fragment expand diffPlus
            middleware = import_string(middleware_path)        #1 fragment expand diffPlus
            handler = middleware(handler)                      #1 fragment expand diffPlus
            												   #1 fragment expand
        response = handler(request)                            #1 fragment expand diffPlus
        return response
			

Time for some middleware...

class WSGIHandler:

    def get_response(self, request):
        view = import_string(settings.THE_VIEW)				   
       	response = view(request)                               #diffMinus
        handler = view 										   #1 fragment fragHighlight diffPlus 
        for middleware_path in reversed(settings.MIDDLEWARE):  #2 fragment  diffPlus fragHighlight
            middleware = import_string(middleware_path)        #3 fragment  diffPlus fragHighlight
            handler = middleware(handler)                      #4 fragment  diffPlus fragHighlight
            												   
        response = handler(request)                            # diffPlus
        return response
			

Time for some middleware...

class WSGIHandler:

    def get_response(self, request):
        view = import_string(settings.THE_VIEW)				   #1 fragment fragHighlight
       	response = view(request)                               #1 fragment fragHighlight diffMinus
        handler = view 										   #1 fragment fragHighlight diffPlus 
        for middleware_path in reversed(settings.MIDDLEWARE):  #1 fragment  diffPlus fragHighlight
            middleware = import_string(middleware_path)        #1 fragment  diffPlus fragHighlight
            handler = middleware(handler)                      #1 fragment  diffPlus fragHighlight
            												   
        response = handler(request)                            #diffPlus
        return response               						   
			

Time for some middleware...

class WSGIHandler:
0000000000000000000000000000000000000000000000000000000000000  #invisible
	def __init__(self): 									   #5 fragment expand diffPlus
		self.load_middleware() 								   #5 fragment expand diffPlus
															   #5 fragment expand
	def load_middleware(self):								   #2 fragment expand diffPlus
        view = import_string(settings.THE_VIEW)				   #2 fragment expand diffPlus
        handler = view 										   #2 fragment expand diffPlus
        for middleware_path in reversed(settings.MIDDLEWARE):  #2 fragment expand diffPlus
            middleware = import_string(middleware_path)        #2 fragment expand diffPlus
            handler = middleware(handler)                      #2 fragment expand diffPlus
            												   #3 fragment expand
        self._middleware_chain = handler                       #3 fragment expand diffPlus
        													   #2 fragment expand
    def get_response(self, request):
        view = import_string(settings.THE_VIEW)				   #1 fragment collapse
       	response = view(request)                               #1 fragment diffMinus collapse 
        handler = view 										   #1 fragment collapse diffPlus 
        for middleware_path in reversed(settings.MIDDLEWARE):  #1 fragment collapse diffPlus
            middleware = import_string(middleware_path)        #1 fragment collapse diffPlus
            handler = middleware(handler)                      #1 fragment collapse diffPlus
            												   #1 fragment collapse
        response = handler(request)                            #4 fragment collapse diffPlus
        response = self._middleware_chain(request)             #4 fragment expand  diffPlus
        return response
			
class WSGIHandler:								 
                                                             
	def __init__(self): 									 
		self.load_middleware() 								 
															 
	def load_middleware(self):								 
        view = import_string(settings.THE_VIEW)				 
        handler = view 										 
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)      
            handler = middleware(handler)
            
            if handler is None:												    #1 fragment expand diffPlus
                raise ImproperlyConfigured(									    #1 fragment expand diffPlus
                    'Middleware factory %s returned None.' % middleware_path    #1 fragment expand diffPlus
                )               												#1 fragment expand diffPlus 
            												 					#1 fragment expand
        self._middleware_chain = handler                     

    def get_response(self, request):
        response = self._middleware_chain(request)
        return response
			
1. The server loads up WSGISERVER 2. A request comes along def load_middleware(): ... self._middleware_chain = handler def __call__(self, environ, start_request): ... response = self.get_response(request) ... return response def get_response(self, request): response = self._middleware_chain(request) ... return response
class WSGIHandler:

	def load_middleware(self):								 
        view = import_string(settings.THE_VIEW)	                 #1 fragment fragDiffMinus			 
        handler = view 										     #1 fragment fragDiffMinus
        handler = self._get_response                             #2 fragment expand diffPlus
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)      
            handler = middleware(handler)

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )               												

        self._middleware_chain = handler

    def _get_response(self, request):                            #2 fragment expand diffPlus
    	view = import_string(settings.THE_VIEW)			 	     #2 fragment expand diffPlus
        return view(request) 									 #2 fragment expand diffPlus
        	
class WSGIHandler:

	def load_middleware(self):								 
        view = import_string(settings.THE_VIEW)	                 #diffMinus			 
        handler = view 										     #diffMinus
        handler = self._get_response                             #diffPlus
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)      
            handler = middleware(handler)

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )                    
            												 
        self._middleware_chain = handler

    def _get_response(self, request):                               #  diffPlus
        if hasattr(request, 'urlconf'):                             #1 fragment diffPlus fragHighlight
            urlconf = request.urlconf                               #1 fragment diffPlus fragHighlight
            set_urlconf(urlconf)								    #1 fragment diffPlus fragHighlight
            resolver = get_resolver(urlconf)					    #1 fragment diffPlus fragHighlight
        else:													    #2 fragment diffPlus fragHighlight
            resolver = get_resolver()							    #2 fragment diffPlus fragHighlight
        resolver_match = resolver.resolve(request.path_info)	    #3 fragment diffPlus fragHighlight
        request.resolver_match = resolver_match					    #4 fragment diffPlus fragHighlight
        														    # diffPlus
        callback, callback_args, callback_kwargs = resolver_match   #5 fragment diffPlus fragHighlight
        return callback(request, *callback_args, **callback_kwargs) #6 fragment diffPlus fragHighlight
        	
class WSGIHandler:

	def load_middleware(self):								 
        view = import_string(settings.THE_VIEW)	                 #diffMinus			 
        handler = view 										     #diffMinus
        handler = self._get_response                             #diffPlus
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)      
            handler = middleware(handler)

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )                     
            												 
        self._middleware_chain = handler

    def _get_response(self, request):                               # diffPlus
        if hasattr(request, 'urlconf'):                             #1 fragment diffPlus fragHighlight 
            urlconf = request.urlconf                               #1 fragment diffPlus fragHighlight
            set_urlconf(urlconf)								    #1 fragment diffPlus fragHighlight
            resolver = get_resolver(urlconf)					    #1 fragment diffPlus fragHighlight
        else:													    #1 fragment diffPlus fragHighlight
            resolver = get_resolver()							    #1 fragment diffPlus fragHighlight
        resolver_match = resolver.resolve(request.path_info)	    #1 fragment diffPlus fragHighlight
        request.resolver_match = resolver_match					    #1 fragment diffPlus fragHighlight
        														    # diffPlus
        callback, callback_args, callback_kwargs = resolver_match   # diffPlus
        return callback(request, *callback_args, **callback_kwargs) # diffPlus
        	
class WSGIHandler:

	def load_middleware(self):								 
        view = import_string(settings.THE_VIEW)	                 #diffMinus			 
        handler = view 										     #diffMinus
        handler = self._get_response                             #diffPlus
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)      
            handler = middleware(handler)     

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )                 
            												 
        self._middleware_chain = handler

    def _get_response(self, request):                               # fragment diffPlus
        if hasattr(request, 'urlconf'):                             #1 fragment diffPlus collapse 
            urlconf = request.urlconf                               #1 fragment diffPlus collapse
            set_urlconf(urlconf)								    #1 fragment diffPlus collapse
            resolver = get_resolver(urlconf)					    #1 fragment diffPlus collapse
        else:													    #1 fragment diffPlus collapse
            resolver = get_resolver()							    #1 fragment diffPlus collapse
        resolver_match = resolver.resolve(request.path_info)	    #1 fragment diffPlus collapse
        request.resolver_match = resolver_match					    #1 fragment diffPlus collapse
        														    #1 fragment diffPlus collapse
        callback, callback_args, callback_kwargs = resolver_match   #1 fragment diffPlus collapse
        callback, callback_args, callback_kwargs = self.resolve_request(request) #1 fragment diffPlus expand
        return callback(request, *callback_args, **callback_kwargs) # diffPlus
        	
class WSGIHandler:

	def load_middleware(self):								 
        handler = self._get_response
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)      
            handler = middleware(handler) 

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )                     
            												 
        self._middleware_chain = handler

    def _get_response(self, request):                    
        callback, callback_args, callback_kwargs = self.resolve_request(request)
        return callback(request, *callback_args, **callback_kwargs)
        	

Some typical middleware

class ExampleMiddleware:

	def __init__(self, get_response)
		self.get_response

    def __call__(self, request):
    	if settings.DEBUG:
    		some_useful_debug_stuff()
    	return self.get_response(request)							 
        	
class WSGIHandler:

	def load_middleware(self):								 
        handler = self._get_response
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            handler = middleware(handler)       #1 fragment fragDiffMinus
            try:                        		#1 fragment expand diffPlus
            	handler = middleware(handler)   #1 fragment expand diffPlus
            except MiddlewareNotUsed:		    #1 fragment expand diffPlus 
            	continue           				#1 fragment expand diffPlus

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )     
            												 
        self._middleware_chain = handler

    def _get_response(self, request):                    
        callback, callback_args, callback_kwargs = self.resolve_request(request)
        return callback(request, *callback_args, **callback_kwargs)
        	

Some (better) typical middleware

class ExampleMiddleware:

	def __init__(self, get_response)
		if not settings.DEBUG:            #1 fragment expand diffPlus
			raise MiddlewareNotUsed       #1 fragment expand diffPlus
		self.get_response = get_response

    def __call__(self, request):
    	if settings.DEBUG:                #2 fragment fragDiffMinus 
    		some_useful_debug_stuff()     #2 fragment fragDiffMinus
    	some_useful_debug_stuff()         #2 fragment expand diffPlus
    	return self.get_response(request)					 
        	

What about errors?

class WSGIHandler:

	def load_middleware(self):								 
        handler = self._get_response
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            try:                        	
            	handler = middleware(handler)  
            except MiddlewareNotUsed:		    
            	continue

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )        				  
            												 
        self._middleware_chain = handler

    def _get_response(self, request):                    
        callback, callback_args, callback_kwargs = self.resolve_request(request)
        return callback(request, *callback_args, **callback_kwargs)
        	

A useful decorator...

def convert_exception_to_response(get_response):
    @wraps(get_response)                                       #1 fragment fragHighlight 
    def inner(request):										   #1 fragment fragHighlight
        try:
            response = get_response(request)                   #2 fragment fragHighlight
        except Exception as exc:
            response = response_for_exception(request, exc)    #3 fragment fragHighlight
        return response
    return inner				
        	

What about errors?

class WSGIHandler:

	def load_middleware(self):								 
        handler = self._get_response
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            try:                        	
            	handler = middleware(handler)  
            except MiddlewareNotUsed:		    
            	continue

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )  

        handler = convert_exception_to_response(handler) 	#1 fragment expand diffPlus
        self._middleware_chain = handler

    def _get_response(self, request):                    
        callback, callback_args, callback_kwargs = self.resolve_request(request)
        return callback(request, *callback_args, **callback_kwargs)
        	

What about errors?

Middleware 1 Middleware 2 Middleware 3 Middleware 3 Middleware 2 Middleware 1 View
class WSGIHandler:

	def load_middleware(self):								 
        handler = self._get_response 								#2 fragment fragDiffMinus
        handler = convert_exception_to_response(self._get_response) #2 fragment expand diffPlus
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            try:                        	
            	handler = middleware(handler)  
            except MiddlewareNotUsed:		    
            	continue

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                ) 
            
            handler = convert_exception_to_response(handler)    #1 fragment expand diffPlus

        self._middleware_chain = handler

    def _get_response(self, request):                    
        callback, callback_args, callback_kwargs = resolver_match = self.resolve_request(request)
        return callback(request, *callback_args, **callback_kwargs)
        	

What about errors?

Middleware 1 Middleware 2 Middleware 3 Middleware 3 Middleware 2 Middleware 1 View Convert ExceptionTo response Middleware 1 Middleware 2 Middleware 3 Middleware 3 Middleware 2 Middleware 1 View Convert ExceptionTo response Middleware 1 Middleware 2 Middleware 3 Middleware 3 Middleware 2 Middleware 1 View Convert ExceptionTo response

View Middleware

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 #invisible
class WSGIHandler:
	def load_middleware(self):
		self._view_middleware = []		                              #1 fragment expand diffPlus
        handler = convert_exception_to_response(self._get_response)
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            try:                        	
            	handler = middleware(handler)  
            except MiddlewareNotUsed:		    
            	continue

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )
          	if hasattr(handler, "process_view"):                        #1 fragment expand diffPlus
          		self._view_middleware.insert(0, handler.process_view)   #1 fragment expand diffPlus
            
            handler = convert_exception_to_response(handler)

        self._middleware_chain = handler
    def _get_response(self, request):                    
        response = None                                                                             #3 fragment expand diffPlus
        callback, callback_args, callback_kwargs = self.resolve_request(request)					
        for middleware_method in self._view_middleware: 											#3 fragment expand diffPlus
            response = middleware_method(request, callback, callback_args, callback_kwargs) 		#3 fragment expand diffPlus
            if response: 																			#3 fragment expand diffPlus
                break  																				#3 fragment expand diffPlus																			#3 fragment expand
        if response == None:																			#3 fragment expand diffPlus
        	response = callback(request, *callback_args, **callback_kwargs)							#3 fragment expand diffPlus
        return callback(request, *callback_args, **callback_kwargs)									#3 fragment fragDiffMinus
        return response 																			#3 fragment expand diffPlus
        	

View Middleware

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 #invisible
class WSGIHandler:
    def _get_response(self, request):                    
        response = None                                                             #1 fragment fragHighlight diffPlus
        callback, callback_args, callback_kwargs = self.resolve_request(request)
        for middleware_method in self._view_middleware: 						    #2 fragment fragHighlight diffPlus
            response = middleware_method(request, callback, callback_args, callback_kwargs) #3 fragment fragHighlight diffPlus
            if response: 															#3 fragment fragHighlight diffPlus
                break  																#3 fragment fragHighlight diffPlus																  
        if response == None:															#4 fragment fragHighlight diffPlus
        	response = callback(request, *callback_args, **callback_kwargs)			#4 fragment fragHighlight diffPlus
        return callback(request, *callback_args, **callback_kwargs)				    # diffMinus
        return response 														    #  diffPlus
        	

Exception Middleware

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 #invisible
class WSGIHandler:
	def load_middleware(self):
		self._view_middleware = []
		self._exception_middleware = []                                        #2 fragment expand diffPlus
        handler = convert_exception_to_response(self._get_response)
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            try:                        	
            	handler = middleware(handler)  
            except MiddlewareNotUsed:		    
            	continue

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )
          	if hasattr(handler, "process_view"):
          		self._view_middleware.insert(0, handler.process_view)
          	if hasattr(handler, "process_exception"):                             #2 fragment expand diffPlus
          		self._exception_middleware.append(handler.process_exception)      #2 fragment expand diffPlus
            
            handler = convert_exception_to_response(handler)

        self._middleware_chain = handler
    def _get_response(self, request):                    
        response = No
        callback, callback_args, callback_kwargs = self.resolve_request(request)
         														
        for middleware_method in self._view_middleware: 											
            response = middleware_method(request, callback, callback_args, callback_kwargs) 		
            if response: 																			
                break  																				
                												
        if response == None:																			
        	response = callback(request, *callback_args, **callback_kwargs)		#4 fragment fragDiffMinus
        	try:  																#4 fragment expand diffPlus
        		response = callback(request, *callback_args, **callback_kwargs)	#4 fragment expand diffPlus
        	except Exception as e:  											#4 fragment expand diffPlus
        		response = None  												#4 fragment expand diffPlus
        		for middleware_method in self._exception_middleware:  			#4 fragment expand diffPlus
            		response = middleware_method(request, e)  					#4 fragment expand diffPlus
            		if response:  												#4 fragment expand diffPlus
                		break  													#4 fragment expand diffPlus
                if response is None:  											#4 fragment expand diffPlus
                	raise  														#4 fragment expand diffPlus

        return response 																			
        	

Exception Middleware

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 #invisible
class WSGIHandler:
    def _get_response(self, request):                    
        response = No
        callback, callback_args, callback_kwargs = self.resolve_request(request)
         														
        for middleware_method in self._view_middleware: 											
            response = middleware_method(request, callback, callback_args, callback_kwargs) 		
            if response: 																			
                break  																				
                												
        if response == None:																			
        	response = callback(request, *callback_args, **callback_kwargs)		# diffMinus
        	try:  																#1 fragment fragHighlight diffPlus
        		response = callback(request, *callback_args, **callback_kwargs)	#1 fragment fragHighlight diffPlus
        	except Exception as e:  											#2 fragment fragHighlight diffPlus
        		response = None  												#2 fragment fragHighlight diffPlus
        		for middleware_method in self._exception_middleware:  			#2 fragment fragHighlight diffPlus
            		response = middleware_method(request, e)		   			#2 fragment fragHighlight diffPlus
            		if response:  												#2 fragment fragHighlight diffPlus
                		break  													#2 fragment fragHighlight diffPlus
                if response is None:  											#3 fragment fragHighlight diffPlus
                	raise  														#3 fragment fragHighlight diffPlus

        return response 																			
        	

Exception Middleware

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 #invisible
class WSGIHandler:
    def _get_response(self, request):                    
        response = No
        callback, callback_args, callback_kwargs = self.resolve_request(request)
         														
        for middleware_method in self._view_middleware: 											
            response = middleware_method(request, callback, callback_args, callback_kwargs) 		
            if response: 																			
                break  																				
                												
        if response == None:																			
        	response = callback(request, *callback_args, **callback_kwargs)		# diffMinus
        	try:  																# diffPlus
        		response = callback(request, *callback_args, **callback_kwargs)	# diffPlus
        	except Exception as e:  											# diffPlus
        		response = None  												#1 fragment collapse diffPlus
        		for middleware_method in self._exception_middleware:  			#1 fragment collapse diffPlus
            		response = middleware_method(request, e)  					#1 fragment collapse diffPlus
            		if response:  												#1 fragment collapse diffPlus
                		break  													#1 fragment collapse diffPlus
                response = self.process_exception_by_middleware(request, e) 	#1 expand diffPlus
                if response is None:  											# diffPlus
                	raise  														# diffPlus

        return response 																			
        	

Template Middleware

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 #invisible
class WSGIHandler:
	def load_middleware(self):
		self._view_middleware = []
		self._exception_middleware = []
		self._template_response_middleware = []                             #2 fragment expand diffPlus
        handler = convert_exception_to_response(self._get_response)
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            try:                        	
            	handler = middleware(handler)  
            except MiddlewareNotUsed:		    
            	continue

            if handler is None:												   
                raise ImproperlyConfigured(									   
                    'Middleware factory %s returned None.' % middleware_path   
                )
          	if hasattr(handler, "process_view"):
          		self._view_middleware.insert(0, handler.process_view)
          	if hasattr(handler, "process_exception"):
          		self._exception_middleware.append(handler.process_exception)
          	if hasattr(handler, "process_template_response"):                              #2 fragment expand diffPlus
          		self._template_response_middleware.append(handler.process_template_response)                              #2 fragment expand diffPlus
            
            handler = convert_exception_to_response(handler)

        self._middleware_chain = handler
    def _get_response(self, request):                    
        response = No
        callback, callback_args, callback_kwargs = self.resolve_request(request)			
        for middleware_method in self._view_middleware: 											
            response = middleware_method(request, callback, callback_args, callback_kwargs) 		
            if response: 																			
                break       												
        if response == None:																			
        	try:  																
        		response = callback(request, *callback_args, **callback_kwargs)
        	except Exception as e:  										
                response = self.process_exception_by_middleware(request, e) 	
                if response is None:  										
                	raise
        if hasattr(response, 'render') and callable(response.render):    	#4 fragment expand diffPlus
            for middleware_method in self._template_response_middleware:    #4 fragment expand diffPlus
                response = middleware_method(request, response)    			#4 fragment expand diffPlus
            try:    														#4 fragment expand diffPlus
                response = response.render()    							#4 fragment expand diffPlus
            except Exception as e:    										#4 fragment expand diffPlus
                response = self.process_exception_by_middleware(e, request) #4 fragment expand diffPlus
                if response is None:    									#4 fragment expand diffPlus
                    raise												    #4 fragment expand diffPlus

        return response 																			
        	
Middleware 1 Middleware 2 Middleware 3 Middleware 3 Middleware 2 Middleware 1 View URL Resolution ViewMiddleware 1 ViewMiddleware 2 ViewMiddleware 3 ExceptionMiddleware 3 ExceptionMiddleware 2 ExceptionMiddleware 1 TemplateMiddleware 1 TemplateMiddleware 2 TemplateMiddleware 3 ExceptionMiddleware 1 ExceptionMiddleware 2 ExceptionMiddleware 3 (if View middleware return a response) (View Exception) RaiseException RaiseException

One more thing...

class WSGIHandler:

    def _get_response(self, request):                    
        response = None
        callback, callback_args, callback_kwargs = self.resolve_request(request)			
        for middleware_method in self._view_middleware: 											
            response = middleware_method(request, callback, callback_args, callback_kwargs) 		
            if response: 																			
                break       												
        if response == None:
        	wrapped_callback = self.make_view_atomic(callback)							   #1 fragment expand diffPlus
        	try:  																
        		response = callback(request, *callback_args, **callback_kwargs)            #1 fragment fragDiffMinus
        		response = wrapped_callback(request, *callback_args, **callback_kwargs)	   #1 fragment expand diffPlus
        	except Exception as e:  										
                response = self.process_exception_by_middleware(request, e) 	
                if response is None:  										
                	raise
        if hasattr(response, 'render') and callable(response.render):    	
            for middleware_method in self._template_response_middleware:    
                response = middleware_method(request, response)    			
            try:    														
                response = response.render()    							
            except Exception as e:    										
                response = self.process_exception_by_middleware(e, request) 
                if response is None:    									
                    raise												    

        return response 																			
        	

The End

Thankyou for listening