SlideShare a Scribd company logo

Behind the curtain - How Django handles a request

Does Django sometimes feel like Magic to you? In this presentation, we will peek behind the curtain to understand the wizardry that turns an HTTP request into a response. Despite rumors to the contrary, Django does not actually involve any magic - it's just code! We will dive deep into this code and trace the exact steps that turn an HTTP request into a response. On this exciting journey, you'll get a high-level overview of the different components that make up Django and dissect elegant code constructs. Originally presented at DjangoCon Europe 2018 in Heidelberg, Germany.

1 of 133
Download to read offline
Behind the curtain
How Django handles a request
Daniel Hepper
About this tutorial
• not a top-down Django tutorial

• for people who want to get to the bottom of things
What we'll cover
• what is Django?

• dissecting the tiniest Django web app

• the same app, but more complicated
About me
Daniel Hepper

• degree in computer science

• freelancing for 7 years

• first contact with Django
around 0.95

• NOT a core developer

• varying amounts beard
What is Django
The web framework for
perfectionists with deadlines
Django makes it easier to build better Web apps
more quickly and with less code.

Recommended

Django interview Questions| Edureka
Django interview  Questions| EdurekaDjango interview  Questions| Edureka
Django interview Questions| EdurekaEdureka!
 
강좌 개요
강좌 개요강좌 개요
강좌 개요chcbaram
 
Seven Habits of Highly Effective Jenkins Users (2014 edition!)
Seven Habits of Highly Effective Jenkins Users (2014 edition!)Seven Habits of Highly Effective Jenkins Users (2014 edition!)
Seven Habits of Highly Effective Jenkins Users (2014 edition!)Andrew Bayer
 
Dicoding Developer Coaching #34: Android | Modular Android App dengan Dynamic...
Dicoding Developer Coaching #34: Android | Modular Android App dengan Dynamic...Dicoding Developer Coaching #34: Android | Modular Android App dengan Dynamic...
Dicoding Developer Coaching #34: Android | Modular Android App dengan Dynamic...DicodingEvent
 
Introduction to ansible
Introduction to ansibleIntroduction to ansible
Introduction to ansibleOmid Vahdaty
 

More Related Content

What's hot

Working Remotely (via SSH) Rocks!
Working Remotely (via SSH) Rocks!Working Remotely (via SSH) Rocks!
Working Remotely (via SSH) Rocks!Kent Chen
 
[24]안드로이드 웹뷰의 모든것
[24]안드로이드 웹뷰의 모든것[24]안드로이드 웹뷰의 모든것
[24]안드로이드 웹뷰의 모든것NAVER Engineering
 
Best practices for ansible
Best practices for ansibleBest practices for ansible
Best practices for ansibleGeorge Shuklin
 
Clean architecture
Clean architectureClean architecture
Clean architectureandbed
 
Linux 강의자료 ed10
Linux 강의자료 ed10Linux 강의자료 ed10
Linux 강의자료 ed10hungrok
 
강좌 03 개발환경 구축
강좌 03 개발환경 구축강좌 03 개발환경 구축
강좌 03 개발환경 구축chcbaram
 
Introduction to git flow
Introduction to git flowIntroduction to git flow
Introduction to git flowKnoldus Inc.
 
Using Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsUsing Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsGlobalLogic Ukraine
 
강좌 01 ARM 프로세서 개요
강좌 01 ARM 프로세서 개요강좌 01 ARM 프로세서 개요
강좌 01 ARM 프로세서 개요chcbaram
 
Android is NOT just 'Java on Linux'
Android is NOT just 'Java on Linux'Android is NOT just 'Java on Linux'
Android is NOT just 'Java on Linux'Tetsuyuki Kobayashi
 
Build Your Own Angular Component Library
Build Your Own Angular Component LibraryBuild Your Own Angular Component Library
Build Your Own Angular Component LibraryCarlo Bonamico
 
Natalie's Alice in Wonderland Syndrome project
Natalie's Alice in Wonderland Syndrome project Natalie's Alice in Wonderland Syndrome project
Natalie's Alice in Wonderland Syndrome project psy101online
 
Introduction to Google Guice
Introduction to Google GuiceIntroduction to Google Guice
Introduction to Google GuiceKnoldus Inc.
 
CSW2017 Qinghao tang+Xinlei ying vmware_escape_final
CSW2017 Qinghao tang+Xinlei ying vmware_escape_finalCSW2017 Qinghao tang+Xinlei ying vmware_escape_final
CSW2017 Qinghao tang+Xinlei ying vmware_escape_finalCanSecWest
 
사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.
사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.
사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.flashscope
 

What's hot (20)

Working Remotely (via SSH) Rocks!
Working Remotely (via SSH) Rocks!Working Remotely (via SSH) Rocks!
Working Remotely (via SSH) Rocks!
 
[24]안드로이드 웹뷰의 모든것
[24]안드로이드 웹뷰의 모든것[24]안드로이드 웹뷰의 모든것
[24]안드로이드 웹뷰의 모든것
 
Unicode basics in python
Unicode basics in pythonUnicode basics in python
Unicode basics in python
 
Best practices for ansible
Best practices for ansibleBest practices for ansible
Best practices for ansible
 
Clean architecture
Clean architectureClean architecture
Clean architecture
 
Linux 강의자료 ed10
Linux 강의자료 ed10Linux 강의자료 ed10
Linux 강의자료 ed10
 
강좌 03 개발환경 구축
강좌 03 개발환경 구축강좌 03 개발환경 구축
강좌 03 개발환경 구축
 
NodeJS for Beginner
NodeJS for BeginnerNodeJS for Beginner
NodeJS for Beginner
 
Introduction to git flow
Introduction to git flowIntroduction to git flow
Introduction to git flow
 
Using Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsUsing Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side Effects
 
Jenkins CI
Jenkins CIJenkins CI
Jenkins CI
 
강좌 01 ARM 프로세서 개요
강좌 01 ARM 프로세서 개요강좌 01 ARM 프로세서 개요
강좌 01 ARM 프로세서 개요
 
Android is NOT just 'Java on Linux'
Android is NOT just 'Java on Linux'Android is NOT just 'Java on Linux'
Android is NOT just 'Java on Linux'
 
Build Your Own Angular Component Library
Build Your Own Angular Component LibraryBuild Your Own Angular Component Library
Build Your Own Angular Component Library
 
Natalie's Alice in Wonderland Syndrome project
Natalie's Alice in Wonderland Syndrome project Natalie's Alice in Wonderland Syndrome project
Natalie's Alice in Wonderland Syndrome project
 
Android local sockets in native code
Android local sockets in native code Android local sockets in native code
Android local sockets in native code
 
Introduction to Google Guice
Introduction to Google GuiceIntroduction to Google Guice
Introduction to Google Guice
 
Django Girls Tutorial
Django Girls TutorialDjango Girls Tutorial
Django Girls Tutorial
 
CSW2017 Qinghao tang+Xinlei ying vmware_escape_final
CSW2017 Qinghao tang+Xinlei ying vmware_escape_finalCSW2017 Qinghao tang+Xinlei ying vmware_escape_final
CSW2017 Qinghao tang+Xinlei ying vmware_escape_final
 
사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.
사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.
사용자가 업로드한 사진의 마커를 이용해 OpenCV + aruco로 일정한 형태로 만들고 영상으로 만들어 보았다.
 

Similar to Behind the curtain - How Django handles a request

Django for mobile applications
Django for mobile applicationsDjango for mobile applications
Django for mobile applicationsHassan Abid
 
Testing in AngularJS
Testing in AngularJSTesting in AngularJS
Testing in AngularJSPeter Drinnan
 
gDayX 2013 - Advanced AngularJS - Nicolas Embleton
gDayX 2013 - Advanced AngularJS - Nicolas EmbletongDayX 2013 - Advanced AngularJS - Nicolas Embleton
gDayX 2013 - Advanced AngularJS - Nicolas EmbletonGeorge Nguyen
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineYared Ayalew
 
gDayX - Advanced angularjs
gDayX - Advanced angularjsgDayX - Advanced angularjs
gDayX - Advanced angularjsgdgvietnam
 
Kogito: cloud native business automation
Kogito: cloud native business automationKogito: cloud native business automation
Kogito: cloud native business automationMario Fusco
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и DjangoMoscowDjango
 
Writing automation tests with python selenium behave pageobjects
Writing automation tests with python selenium behave pageobjectsWriting automation tests with python selenium behave pageobjects
Writing automation tests with python selenium behave pageobjectsLeticia Rss
 
Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Jacob Kaplan-Moss
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexyananelson
 
Google app-engine-with-python
Google app-engine-with-pythonGoogle app-engine-with-python
Google app-engine-with-pythonDeepak Garg
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsRichard Rodger
 
國民雲端架構 Django + GAE
國民雲端架構 Django + GAE國民雲端架構 Django + GAE
國民雲端架構 Django + GAEWinston Chen
 
Angular Intermediate
Angular IntermediateAngular Intermediate
Angular IntermediateLinkMe Srl
 

Similar to Behind the curtain - How Django handles a request (20)

Django for mobile applications
Django for mobile applicationsDjango for mobile applications
Django for mobile applications
 
Testing in AngularJS
Testing in AngularJSTesting in AngularJS
Testing in AngularJS
 
Django tricks (2)
Django tricks (2)Django tricks (2)
Django tricks (2)
 
gDayX 2013 - Advanced AngularJS - Nicolas Embleton
gDayX 2013 - Advanced AngularJS - Nicolas EmbletongDayX 2013 - Advanced AngularJS - Nicolas Embleton
gDayX 2013 - Advanced AngularJS - Nicolas Embleton
 
React django
React djangoReact django
React django
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App Engine
 
gDayX - Advanced angularjs
gDayX - Advanced angularjsgDayX - Advanced angularjs
gDayX - Advanced angularjs
 
Kogito: cloud native business automation
Kogito: cloud native business automationKogito: cloud native business automation
Kogito: cloud native business automation
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и Django
 
Writing automation tests with python selenium behave pageobjects
Writing automation tests with python selenium behave pageobjectsWriting automation tests with python selenium behave pageobjects
Writing automation tests with python selenium behave pageobjects
 
Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexy
 
Google app-engine-with-python
Google app-engine-with-pythonGoogle app-engine-with-python
Google app-engine-with-python
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.js
 
20120816 nodejsdublin
20120816 nodejsdublin20120816 nodejsdublin
20120816 nodejsdublin
 
國民雲端架構 Django + GAE
國民雲端架構 Django + GAE國民雲端架構 Django + GAE
國民雲端架構 Django + GAE
 
Angular Intermediate
Angular IntermediateAngular Intermediate
Angular Intermediate
 
Angularjs
AngularjsAngularjs
Angularjs
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 

Recently uploaded

What are the Reasons for Tracking the Attendance of the Employees?
What are the Reasons for Tracking the Attendance of the Employees?What are the Reasons for Tracking the Attendance of the Employees?
What are the Reasons for Tracking the Attendance of the Employees?NYGGS Automation Suite
 
Role of DevOps in SaaS product Development.pdf.pptx
Role of DevOps in SaaS product Development.pdf.pptxRole of DevOps in SaaS product Development.pdf.pptx
Role of DevOps in SaaS product Development.pdf.pptxMindInventory
 
LLMOps with Azure Machine Learning prompt flow
LLMOps with Azure Machine Learning prompt flowLLMOps with Azure Machine Learning prompt flow
LLMOps with Azure Machine Learning prompt flowNaoki (Neo) SATO
 
Workshop híbrido: Stream Processing con Flink
Workshop híbrido: Stream Processing con FlinkWorkshop híbrido: Stream Processing con Flink
Workshop híbrido: Stream Processing con Flinkconfluent
 
Automation for Bonterra Impact Management (fka Apricot)
Automation for Bonterra Impact Management (fka Apricot)Automation for Bonterra Impact Management (fka Apricot)
Automation for Bonterra Impact Management (fka Apricot)Jeffrey Haguewood
 
No more Dockerfiles? Buildpacks to help you ship your image!
No more Dockerfiles? Buildpacks to help you ship your image!No more Dockerfiles? Buildpacks to help you ship your image!
No more Dockerfiles? Buildpacks to help you ship your image!Anthony Dahanne
 
OpenChain AI Study Group - North America and Europe - 2024-02-20
OpenChain AI Study Group - North America and Europe - 2024-02-20OpenChain AI Study Group - North America and Europe - 2024-02-20
OpenChain AI Study Group - North America and Europe - 2024-02-20Shane Coughlan
 
killingcamp longest common subsequence.pdf
killingcamp longest common subsequence.pdfkillingcamp longest common subsequence.pdf
killingcamp longest common subsequence.pdfssuser82c38d
 
Open Source vs Closed Source LLMs. Pros and Cons
Open Source vs Closed Source LLMs. Pros and ConsOpen Source vs Closed Source LLMs. Pros and Cons
Open Source vs Closed Source LLMs. Pros and ConsSprings
 
killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이
killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이
killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이ssuser82c38d
 
Implementing Docker Containers with Windows Server 2019
Implementing Docker Containers with Windows Server 2019Implementing Docker Containers with Windows Server 2019
Implementing Docker Containers with Windows Server 2019VICTOR MAESTRE RAMIREZ
 
Machine Learning Basics for Dummies (no math!)
Machine Learning Basics for Dummies (no math!)Machine Learning Basics for Dummies (no math!)
Machine Learning Basics for Dummies (no math!)Dmitry Zinoviev
 
Joseph Yoder : Being Agile about Architecture
Joseph Yoder : Being Agile about ArchitectureJoseph Yoder : Being Agile about Architecture
Joseph Yoder : Being Agile about ArchitectureHironori Washizaki
 
Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...
Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...
Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...Alluxio, Inc.
 
killing camp week 6 problem - maximal matrix.pdf
killing camp week 6 problem - maximal matrix.pdfkilling camp week 6 problem - maximal matrix.pdf
killing camp week 6 problem - maximal matrix.pdfssuser82c38d
 
The Top Outages of 2023: Analyses and Takeaways
The Top Outages of 2023: Analyses and TakeawaysThe Top Outages of 2023: Analyses and Takeaways
The Top Outages of 2023: Analyses and TakeawaysThousandEyes
 
How AI is preventing account fraud at web scale
How AI is preventing account fraud at web scaleHow AI is preventing account fraud at web scale
How AI is preventing account fraud at web scaleAmir Moghimi
 
Passbolt Introduction and Usage for secret managment
Passbolt Introduction and Usage for secret managmentPassbolt Introduction and Usage for secret managment
Passbolt Introduction and Usage for secret managmentThierry Gayet
 
Welcome to AltTask - the nexus where innovation converges with empowerment!
Welcome to AltTask - the nexus where innovation converges with empowerment!Welcome to AltTask - the nexus where innovation converges with empowerment!
Welcome to AltTask - the nexus where innovation converges with empowerment!alttaskcom
 
Agile & Scrum, Certified Scrum Master! Crash Course
Agile & Scrum,  Certified Scrum Master! Crash CourseAgile & Scrum,  Certified Scrum Master! Crash Course
Agile & Scrum, Certified Scrum Master! Crash CourseRohan Chandane
 

Recently uploaded (20)

What are the Reasons for Tracking the Attendance of the Employees?
What are the Reasons for Tracking the Attendance of the Employees?What are the Reasons for Tracking the Attendance of the Employees?
What are the Reasons for Tracking the Attendance of the Employees?
 
Role of DevOps in SaaS product Development.pdf.pptx
Role of DevOps in SaaS product Development.pdf.pptxRole of DevOps in SaaS product Development.pdf.pptx
Role of DevOps in SaaS product Development.pdf.pptx
 
LLMOps with Azure Machine Learning prompt flow
LLMOps with Azure Machine Learning prompt flowLLMOps with Azure Machine Learning prompt flow
LLMOps with Azure Machine Learning prompt flow
 
Workshop híbrido: Stream Processing con Flink
Workshop híbrido: Stream Processing con FlinkWorkshop híbrido: Stream Processing con Flink
Workshop híbrido: Stream Processing con Flink
 
Automation for Bonterra Impact Management (fka Apricot)
Automation for Bonterra Impact Management (fka Apricot)Automation for Bonterra Impact Management (fka Apricot)
Automation for Bonterra Impact Management (fka Apricot)
 
No more Dockerfiles? Buildpacks to help you ship your image!
No more Dockerfiles? Buildpacks to help you ship your image!No more Dockerfiles? Buildpacks to help you ship your image!
No more Dockerfiles? Buildpacks to help you ship your image!
 
OpenChain AI Study Group - North America and Europe - 2024-02-20
OpenChain AI Study Group - North America and Europe - 2024-02-20OpenChain AI Study Group - North America and Europe - 2024-02-20
OpenChain AI Study Group - North America and Europe - 2024-02-20
 
killingcamp longest common subsequence.pdf
killingcamp longest common subsequence.pdfkillingcamp longest common subsequence.pdf
killingcamp longest common subsequence.pdf
 
Open Source vs Closed Source LLMs. Pros and Cons
Open Source vs Closed Source LLMs. Pros and ConsOpen Source vs Closed Source LLMs. Pros and Cons
Open Source vs Closed Source LLMs. Pros and Cons
 
killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이
killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이
killingcamp 광고삽입문제 풀이, killingcamp 광고삽입문제 풀이
 
Implementing Docker Containers with Windows Server 2019
Implementing Docker Containers with Windows Server 2019Implementing Docker Containers with Windows Server 2019
Implementing Docker Containers with Windows Server 2019
 
Machine Learning Basics for Dummies (no math!)
Machine Learning Basics for Dummies (no math!)Machine Learning Basics for Dummies (no math!)
Machine Learning Basics for Dummies (no math!)
 
Joseph Yoder : Being Agile about Architecture
Joseph Yoder : Being Agile about ArchitectureJoseph Yoder : Being Agile about Architecture
Joseph Yoder : Being Agile about Architecture
 
Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...
Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...
Alluxio Monthly Webinar | Why a Multi-Cloud Strategy Matters for Your AI Plat...
 
killing camp week 6 problem - maximal matrix.pdf
killing camp week 6 problem - maximal matrix.pdfkilling camp week 6 problem - maximal matrix.pdf
killing camp week 6 problem - maximal matrix.pdf
 
The Top Outages of 2023: Analyses and Takeaways
The Top Outages of 2023: Analyses and TakeawaysThe Top Outages of 2023: Analyses and Takeaways
The Top Outages of 2023: Analyses and Takeaways
 
How AI is preventing account fraud at web scale
How AI is preventing account fraud at web scaleHow AI is preventing account fraud at web scale
How AI is preventing account fraud at web scale
 
Passbolt Introduction and Usage for secret managment
Passbolt Introduction and Usage for secret managmentPassbolt Introduction and Usage for secret managment
Passbolt Introduction and Usage for secret managment
 
Welcome to AltTask - the nexus where innovation converges with empowerment!
Welcome to AltTask - the nexus where innovation converges with empowerment!Welcome to AltTask - the nexus where innovation converges with empowerment!
Welcome to AltTask - the nexus where innovation converges with empowerment!
 
Agile & Scrum, Certified Scrum Master! Crash Course
Agile & Scrum,  Certified Scrum Master! Crash CourseAgile & Scrum,  Certified Scrum Master! Crash Course
Agile & Scrum, Certified Scrum Master! Crash Course
 

Behind the curtain - How Django handles a request

  • 1. Behind the curtain How Django handles a request Daniel Hepper
  • 2. About this tutorial • not a top-down Django tutorial • for people who want to get to the bottom of things
  • 3. What we'll cover • what is Django? • dissecting the tiniest Django web app • the same app, but more complicated
  • 4. About me Daniel Hepper • degree in computer science • freelancing for 7 years • first contact with Django around 0.95 • NOT a core developer • varying amounts beard
  • 6. The web framework for perfectionists with deadlines Django makes it easier to build better Web apps more quickly and with less code.
  • 7. Web apps • web app • Django project • django-admin.py startproject • Django app • module, part of an web app • might be re-usable: re-usable app • python manage.py startapp
  • 9. Web Framework • you take things from a library,
 you put something in a framework • "Don't call us, we call you" • But you have to tell us your number
 you have to provide an entrypoint
  • 12. Web Framework • turn HTTP requests into HTTP response
  • 14. HTTP Client HTTP Request HTTP Response HTTP Server
  • 15. HTTP-Request & Reponse GET / HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: curl/7.54.0 Accept: */* HTTP/1.0 200 OK Date: Sat, 26 May 2018 07:27:52 GMT Server: WSGIServer/0.2 CPython/3.6.4 Content-Type: text/html; charset=utf-8 Hello world
  • 21. WSGI • Defined in PEP-333 / PEP-3333 • "A [...] standard interface between web servers and Python web applications or frameworks, to promote web application portability across a variety of web servers." • "WSGI is a tool for framework and server developers"
  • 23. WSGI Application • Callable that accepts two arguments • a function, method, class, instance with a __call__ method • result = application(environ, start_response) • environ: dictionary object, containing CGI-style environment variables • start_response: callable, accepting two required positional arguments, third optional • def start_response(status, response_headers, exc_info=None): • When called by the server, the application object must return an iterable yielding zero or more bytestrings
  • 24. Hello WSGI HELLO_WORLD = b"Hello world!n" def simple_app(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [HELLO_WORLD]
  • 25. The web framework for perfectionists with deadlines Django makes it easier to build better Web apps more quickly and with less code. WSGI
  • 27. (venv)$ pip install django==2.0.5 (venv)$ django-admin.py startproject default (venv)$ tree default default ├── manage.py └── default ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py (venv)$ cat default/default/settings.py
  • 28. """ Django settings for mysite project... """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '-^oi_8%de()$d3qqa_4fgwds#&nlfn2(j-@_hu(j-m7-+-@q@p' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', ... 'django.contrib.staticfiles', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', ... 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'default.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', "Django is too complicated!"
  • 29. Web development is complicated Django offers reasonable defaults to make your life easier
  • 31. All you need is... • a view • an URLConf • settings • a WSGI application object
  • 33. views.py from django.http import HttpResponse def hello(request): return HttpResponse('Hello world')
  • 34. urls.py from django.urls import path from . import views urlpatterns = [ path('', views) ]
  • 36. wsgi.py import os from django.core.wsgi import get_wsgi_application os.environ.setdefault( "DJANGO_SETTINGS_MODULE", "simple.settings" ) application = get_wsgi_application()
  • 37. Running a Django web application • job of a WSGI server • two phases • import the application object • call the application object for each request
  • 38. A simple WSGI server from wsgiref.simple_server import make_server from simple.wsgi import application httpd = make_server('127.0.0.1', 8000, application) print("Serving HTTP on port 8000...") httpd.handle_request()
  • 39. (venv)$ tree simple . ├── server.py └── simple ├── __init__.py ├── __pycache__ ├── settings.py ├── urls.py ├── views.py └── wsgi.py
  • 40. DEMO
  • 44. import os from django.core.wsgi import get_wsgi_application os.environ.setdefault( "DJANGO_SETTINGS_MODULE", "simple.settings" ) application = get_wsgi_application() wsgi.py
  • 45. import django from django.core.handlers.wsgi import WSGIHandler def get_wsgi_application(): """ The public interface to Django's WSGI support. Return a WSGI callable. Avoids making django.core.handlers.WSGIHandler a public API, in case the internal WSGI implementation changes or moves in the future. """ django.setup(set_prefix=False) return WSGIHandler() django/core/wsgi.py
  • 46. from django.utils.version import get_version VERSION = (2, 0, 0, 'final', 0) __version__ = get_version(VERSION) def setup(set_prefix=True): """ Configure the settings (this happens as a side effect of accessing the first setting), configure logging and populate the app registry. Set the thread-local urlresolvers script prefix if `set_prefix` is True. """ from django.apps import apps from django.conf import settings from django.urls import set_script_prefix from django.utils.log import configure_logging configure_logging(settings.LOGGING_CONFIG, settings.LOGGING) if set_prefix: set_script_prefix( '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME ) apps.populate(settings.INSTALLED_APPS) django/__init__.py
  • 47. [...] class LazySettings(LazyObject): """ A lazy proxy for either global Django settings or a custom settings object. The user can manually configure settings prior to using them. Otherwise,Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE. """ def __getattr__(self, name): """ Return the value of a setting and cache it in self.__dict__. """ if self._wrapped is empty: self._setup(name) val = getattr(self._wrapped, name) self.__dict__[name] = val return val [...] settings = LazySettings() django/conf/__init__.py
  • 48. [...] class LazySettings(LazyObject): """ A lazy proxy for either global Django settings or a custom settings object. The user can manually configure settings prior to using them. Otherwise,Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE. """ def _setup(self, name=None): """ Load the settings module pointed to by the environment variable. This is used the first time settings are needed, if the user hasn't configured settings manually. """ settings_module = os.environ.get(ENVIRONMENT_VARIABLE) if not settings_module: desc = ("setting %s" % name) if name else "settings" raise ImproperlyConfigured(...) self._wrapped = Settings(settings_module) [...] settings = LazySettings() django/conf/__init__.py
  • 49. [...] class Settings: def __init__(self, settings_module): for setting in dir(global_settings): if setting.isupper(): setattr(self, setting, getattr(global_settings, setting)) [...] mod = importlib.import_module(self.SETTINGS_MODULE) self._explicit_settings = set() for setting in dir(mod): if setting.isupper(): setting_value = getattr(mod, setting) [...] setattr(self, setting, setting_value) [...] [...] settings = LazySettings() django/conf/__init__.py
  • 50. from django.utils.version import get_version VERSION = (2, 0, 0, 'final', 0) __version__ = get_version(VERSION) def setup(set_prefix=True): """ Configure the settings (this happens as a side effect of accessing the first setting), configure logging and populate the app registry. Set the thread-local urlresolvers script prefix if `set_prefix` is True. """ from django.apps import apps from django.conf import settings from django.urls import set_script_prefix from django.utils.log import configure_logging configure_logging(settings.LOGGING_CONFIG, settings.LOGGING) if set_prefix: set_script_prefix( '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME ) apps.populate(settings.INSTALLED_APPS) django/__init__.py
  • 51. import django from django.core.handlers.wsgi import WSGIHandler def get_wsgi_application(): """ The public interface to Django's WSGI support. Return a WSGI callable. Avoids making django.core.handlers.WSGIHandler a public API, in case the internal WSGI implementation changes or moves in the future. """ django.setup(set_prefix=False) return WSGIHandler() django/core/wsgi.py
  • 52. class WSGIHandler(base.BaseHandler): request_class = WSGIRequest def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.load_middleware() def __call__(self, environ, start_response): [...] django/core/handlers/wsgi.py
  • 53. class BaseHandler: [...] def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. """ self._request_middleware = [] self._view_middleware = [] self._template_response_middleware = [] self._response_middleware = [] self._exception_middleware = [] handler = convert_exception_to_response( self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): [...] self._middleware_chain = handler django/core/handlers/base.py
  • 54. class WSGIHandler(base.BaseHandler): [...] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.load_middleware() def __call__(self, environ, start_response): [...] django/core/handlers/wsgi.py
  • 55. import django from django.core.handlers.wsgi import WSGIHandler def get_wsgi_application(): """ The public interface to Django's WSGI support. Return a WSGI callable. Avoids making django.core.handlers.WSGIHandler a public API, in case the internal WSGI implementation changes or moves in the future. """ django.setup(set_prefix=False) return WSGIHandler() django/core/wsgi.py
  • 56. import os from django.core.wsgi import get_wsgi_application os.environ.setdefault( "DJANGO_SETTINGS_MODULE", "simple.settings" ) application = get_wsgi_application() wsgi.py
  • 58. WSGI Application • Callable that accepts two arguments • a function, method, class, instance with a __call__ method • result = application(environ, start_response) • environ: dictionary object, containing CGI-style environment variables • start_response: callable, accepting two required positional arguments, third optional • def start_response(status, response_headers, exc_info=None): • When called by the server, the application object must return an iterable yielding zero or more bytestrings
  • 59. class WSGIHandler(base.BaseHandler): request_class = WSGIRequest [...] def __call__(self, environ, start_response): set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) [...] django/core/handlers/wsgi.py
  • 60. class WSGIRequest(HttpRequest): def __init__(self, environ): [...] django/core/handlers/wsgi.py
  • 61. class WSGIRequest(HttpRequest): def __init__(self, environ): [...] django/core/handlers/wsgi.py
  • 62. class HttpRequest: """A basic HTTP request.""" # The encoding used in GET/POST dicts. None means use default # setting. _encoding = None _upload_handlers = [] def __init__(self): # WARNING: The `WSGIRequest` subclass doesn't call # `super`. # Any variable assignment made here should also happen in # `WSGIRequest.__init__()`. [...] django/core/http/request.py
  • 63. class WSGIRequest(HttpRequest): def __init__(self, environ): script_name = get_script_name(environ) path_info = get_path_info(environ) if not path_info: # Sometimes PATH_INFO exists, but is empty (e.g. # accessing the SCRIPT_NAME URL without a # slash). We really need to operate as if they'd # requested '/'. Not amazingly nice to force # the path like this, but should be harmless. path_info = '/' [...] django/core/handlers/wsgi.py
  • 64. path vs. script_name & path_info • http://mydjangoproject.com/ • http://mydjangoproject.com/polls/ • http://mydjangoprojects.com/project1/ • http://mydjangoprojects.com/project2/polls/ • http://mydjangoprojects.com/project3
  • 65. class WSGIRequest(HttpRequest): def __init__(self, environ): script_name = get_script_name(environ) path_info = get_path_info(environ) if not path_info: # Sometimes PATH_INFO exists, but is empty (e.g. # accessing the SCRIPT_NAME URL without a # slash). We really need to operate as if they'd # requested '/'. Not amazingly nice to force # the path like this, but should be harmless. path_info = '/' [...] def get_script_name(environ): """ Return the equivalent of the HTTP request's SCRIPT_NAME environment variable. If Apache mod_rewrite is used, return what would have been the script name prior to any rewriting (so it's the script name as seen from the client's perspective), unless the FORCE_SCRIPT_NAME setting is set (to anything). """ [...] django/core/handlers/wsgi.py
  • 66. class WSGIRequest(HttpRequest): def __init__(self, environ): script_name = get_script_name(environ) path_info = get_path_info(environ) if not path_info: # Sometimes PATH_INFO exists, but is empty (e.g. # accessing the SCRIPT_NAME URL without a # slash). We really need to operate as if they'd # requested '/'. Not amazingly nice to force # the path like this, but should be harmless. path_info = '/' [...] def get_path_info(environ): """Return the HTTP request's PATH_INFO as a string.""" path_info = get_bytes_from_wsgi(environ, 'PATH_INFO', '/') return repercent_broken_unicode(path_info).decode() django/core/handlers/wsgi.py
  • 67. class WSGIRequest(HttpRequest): def __init__(self, environ): [...] self.environ = environ self.path_info = path_info # be careful to only replace the first slash in the path # because of http://test/something and # http://test//something being different as # stated in http://www.ietf.org/rfc/rfc2396.txt self.path = '%s/%s' % (script_name.rstrip('/'), path_info.replace('/', '', 1)) [...] django/core/handlers/wsgi.py
  • 68. class WSGIRequest(HttpRequest): def __init__(self, environ): [...] self.META = environ self.META['PATH_INFO'] = path_info self.META['SCRIPT_NAME'] = script_name self.method = environ['REQUEST_METHOD'].upper() [...] django/core/handlers/wsgi.py
  • 69. class WSGIRequest(HttpRequest): def __init__(self, environ): [...] self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', '')) if 'charset' in self.content_params: try: codecs.lookup(self.content_params['charset']) except LookupError: pass else: self.encoding = self.content_params['charset'] [...] django/core/handlers/wsgi.py
  • 70. class WSGIRequest(HttpRequest): def __init__(self, environ): [...] self._post_parse_error = False try: content_length = int(environ.get('CONTENT_LENGTH')) except (ValueError, TypeError): content_length = 0 self._stream = LimitedStream(self.environ['wsgi.input'], content_length) self._read_started = False self.resolver_match = None django/core/handlers/wsgi.py
  • 71. class WSGIRequest(HttpRequest): def __init__(self, environ): [...] self._post_parse_error = False try: content_length = int(environ.get('CONTENT_LENGTH')) except (ValueError, TypeError): content_length = 0 self._stream = LimitedStream(self.environ['wsgi.input'], content_length) self._read_started = False self.resolver_match = None class LimitedStream: """ Wrap another stream to disallow reading it past a number of bytes. """ [...] django/core/handlers/wsgi.py
  • 72. class WSGIHandler(base.BaseHandler): request_class = WSGIRequest [...] def __call__(self, environ, start_response): set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) [...] django/core/handlers/wsgi.py
  • 73. class BaseHandler: [...] def get_response(self, request): """ Return an HttpResponse object for the given HttpRequest. """ # Setup default url resolver for this thread set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) django/core/handlers/base.py
  • 74. # Overridden URLconfs for each thread are stored here. _urlconfs = local() [...] def set_urlconf(urlconf_name): """ Set the URLconf for the current thread (overriding the default one in settings). If urlconf_name is None, revert back to the default. """ if urlconf_name: _urlconfs.value = urlconf_name else: if hasattr(_urlconfs, "value"): del _urlconfs.value django/urls/base.py
  • 75. class BaseHandler: [...] def get_response(self, request): """ Return an HttpResponse object for the given HttpRequest. """ # Setup default url resolver for this thread set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) django/core/handlers/base.py
  • 76. class BaseHandler: def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. """ handler = convert_exception_to_response( self._get_response ) [...] self._middleware_chain = handler def get_response(self, request): """ Return an HttpResponse object for the given HttpRequest. """ # Setup default url resolver for this thread set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) django/core/handlers/base.py
  • 77. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happens inside the request/response middleware. """ [...] django/core/handlers/base.py
  • 78. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happens inside the request/response middleware. """ response = None if hasattr(request, 'urlconf'): urlconf = request.urlconf set_urlconf(urlconf) resolver = get_resolver(urlconf) else: resolver = get_resolver() resolver_match = resolver.resolve(request.path_info) callback, callback_args, callback_kwargs = resolver_match request.resolver_match = resolver_match django/core/handlers/base.py
  • 79. class BaseHandler: [...] def _get_response(self, request): [...] callback, callback_args, callback_kwargs = resolver_match [...] # Apply view middleware for middleware_method in self._view_middleware: response = middleware_method(request, callback, ...) if response: break [...] django/core/handlers/base.py
  • 80. class BaseHandler: [...] def _get_response(self, request): [...] callback, callback_args, callback_kwargs = resolver_match [...] # Apply view middleware [...] if response is None: wrapped_callback = self.make_view_atomic(callback) try: response = wrapped_callback( request, *callback_args, **callback_kwargs ) except Exception as e: response = self.process_exception_by_middleware( e, request ) django/core/handlers/base.py
  • 81. class BaseHandler: [...] def _get_response(self, request): [...] callback, callback_args, callback_kwargs = resolver_match [...] # Apply view middleware [...] response = wrapped_callback( request, *callback_args, **callback_kwargs ) # Complain if the view returned None (a common error). [...] # If the response supports deferred rendering, apply # template response middleware and then render the response [...] return response django/core/handlers/base.py
  • 82. class BaseHandler: def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. """ handler = convert_exception_to_response( self._get_response ) [...] self._middleware_chain = handler def get_response(self, request): """ Return an HttpResponse object for the given HttpRequest. """ # Setup default url resolver for this thread set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) django/core/handlers/base.py
  • 83. class BaseHandler: [...] def get_response(self, request): [...] response = self._middleware_chain(request) response._closable_objects.append(request) [...] return response django/core/handlers/base.py
  • 84. class HttpResponseBase: [...] # The WSGI server must call this method upon completion of # the request. # See http://blog.dscpl.com.au/2012/10/obligations-for-calling-close def close(self): for closable in self._closable_objects: try: closable.close() except Exception: pass self.closed = True signals.request_finished.send(sender=self._handler_class) django/http/response.py
  • 85. class BaseHandler: [...] def get_response(self, request): [...] response = self._middleware_chain(request) response._closable_objects.append(request) # If the exception handler returns a TemplateResponse # that has not been rendered, force it to be rendered. if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)): response = response.render() [...] return response django/core/handlers/base.py
  • 86. class BaseHandler: [...] def get_response(self, request): [...] response = self._middleware_chain(request) response._closable_objects.append(request) # If the exception handler returns a TemplateResponse # that has not been rendered, force it to be rendered. if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)): response = response.render() if response.status_code == 404: logger.warning( 'Not Found: %s', request.path, extra={'status_code': 404, 'request': request}) return response django/core/handlers/base.py
  • 87. class WSGIHandler(base.BaseHandler): request_class = WSGIRequest [...] def __call__(self, environ, start_response): set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) [...] django/core/handlers/wsgi.py
  • 88. class WSGIHandler(base.BaseHandler): request_class = WSGIRequest [...] def __call__(self, environ, start_response): [...] response = self.get_response(request) response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase response_headers = list(response.items()) for c in response.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) if (getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper')): response = environ['wsgi.file_wrapper'](response.file_to_str return response django/core/handlers/wsgi.py
  • 92. Function based middleware def simple_middleware(get_response): # One-time configuration and initialization. def middleware(request): # Code to be executed for each request before # the view (and later middleware) are called. response = get_response(request) # Code to be executed for each request/response after # the view is called. return response return middleware
  • 93. Class based middleware class SimpleMiddleware: def __init__(self, get_response): self.get_response = get_response # One-time configuration and initialization. def __call__(self, request): # Code to be executed for each request before # the view (and later middleware) are called. response = self.get_response(request) # Code to be executed for each request/response after # the view is called. return response
  • 94. Additional hooks • process_view(request, view_func, view_args, view_kwargs) • process_exception(request, exception) • process_template_response(request, response)
  • 95. Pre-Django 1.10-style middleware • process_request() • process_response() • django.utils.deprecation.MiddlewareMixin
  • 97. class Middleware1: def __init__(self, get_response): print('> Middleware1.__init__') self.get_response = get_response def __call__(self, request): print('> Middleware1.__call__') response = self.get_response(request) print('< Middleware1.__call__') return response def process_view(self, request, view_func, view_args, view_kwargs): print('> Middleware1.process_view') return None def process_exception(self, request, exception): print('> Middleware1.process_exception') return None def process_template_response(self, request, response): print('> Middleware1.process_template_response') return response middleware/middleware.py
  • 98. SECRET_KEY = 'not-so-secret-123%^&' ROOT_URLCONF = 'middleware.urls' MIDDLEWARE = [ 'middleware.middleware.Middleware1', 'middleware.middleware.Middleware2', 'middleware.middleware.Middleware3', ] middleware/settings.py
  • 100. $ python server.py > Middleware3.__init__ > Middleware2.__init__ > Middleware1.__init__ Serving HTTP on port 8000...
  • 101. class BaseHandler: [...] def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. """ self._request_middleware = [] self._view_middleware = [] self._template_response_middleware = [] self._response_middleware = [] self._exception_middleware = [] handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): [...] self._middleware_chain = handler django/core/handlers/base.py
  • 102. class BaseHandler: [...] def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. """ [...] handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): middleware = import_string(middleware_path) try: mw_instance = middleware(handler) except MiddlewareNotUsed as exc: if settings.DEBUG: [...] continue [...] handler = convert_exception_to_response(mw_instance) self._middleware_chain = handler django/core/handlers/base.py
  • 103. settings.MIDDLEWARE = [ 'middleware.middleware.Middleware1', 'middleware.middleware.Middleware2', 'middleware.middleware.Middleware3', ] handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): middleware = import_string(middleware_path) mw_instance = middleware(handler) handler = convert_exception_to_response(mw_instance) handler = convert_exception_to_response(self._get_response) handler = convert_exception_to_response(Middleware3(handler)) handler = convert_exception_to_response(Middleware2(handler)) handler = convert_exception_to_response(Middleware1(handler))
  • 104. settings.MIDDLEWARE = [ 'middleware1', 'middleware2', 'middleware3', ] handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): middleware = import_string(middleware_path) mw_instance = middleware(handler) handler = convert_exception_to_response(mw_instance) handler = middleware1(middleware2(middleware3(self._get_response)))))))
  • 105. class BaseHandler: [...] def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. """ [...] handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): middleware = import_string(middleware_path) try: mw_instance = middleware(handler) except MiddlewareNotUsed as exc: if settings.DEBUG: [...] continue [...] handler = convert_exception_to_response(mw_instance) self._middleware_chain = handler django/core/handlers/base.py
  • 106. class BaseHandler: [...] def load_middleware(self): [...] for middleware_path in reversed(settings.MIDDLEWARE): [...] if hasattr(mw_instance, 'process_view'): self._view_middleware.insert( 0, mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.append( mw_instance.process_template_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.append( mw_instance.process_exception) handler = convert_exception_to_response(mw_instance) self._middleware_chain = handler django/core/handlers/base.py
  • 107. settings.MIDDLEWARE = [ 'middleware1', 'middleware2', 'middleware3', ] self._view_middleware = [ middleware1_instance.process_view, middleware2_instance.process_view, middleware3_instance.process_view, ] self._template_response_middleware = [ middleware3_instance.process_template_response, middleware2_instance.process_template_response, middleware1_instance.process_template_response, ] self._exception_middleware = [ middleware3_instance.process_exception, middleware2_instance.process_exception, middleware1_instance.process_exception, ]
  • 110. $ python server.py > Middleware3.__init__ > Middleware2.__init__ > Middleware1.__init__ Serving HTTP on port 8000... > Middleware1.__call__ > Middleware2.__call__ > Middleware3.__call__ > Middleware1.process_view > Middleware2.process_view > Middleware3.process_view < Middleware3.__call__ < Middleware2.__call__ < Middleware1.__call__
  • 111. class BaseHandler: def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. """ [...] def get_response(self, request): """ Return an HttpResponse object for the given HttpRequest. """ # Setup default url resolver for this thread set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) middleware1(middleware2(middleware3(self._get_response))))))) django/core/handlers/base.py
  • 113. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ response = None [...] return response django/core/handlers/base.py
  • 114. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ response = None if hasattr(request, 'urlconf'): urlconf = request.urlconf set_urlconf(urlconf) resolver = get_resolver(urlconf) else: resolver = get_resolver() [...] return response django/core/handlers/base.py
  • 115. [...] @functools.lru_cache(maxsize=None) def get_resolver(urlconf=None): if urlconf is None: from django.conf import settings urlconf = settings.ROOT_URLCONF return URLResolver(RegexPattern(r'^/'), urlconf) [...] django/urls/resolvers/base.py
  • 116. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ [...] resolver_match = resolver.resolve(request.path_info) callback, callback_args, callback_kwargs = resolver_match request.resolver_match = resolver_match [...] return response django/core/handlers/base.py
  • 117. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ [...] callback, callback_args, callback_kwargs = resolver_match [...] # Apply view middleware for middleware_method in self._view_middleware: response = middleware_method(request, callback, callback_args, callback_kwargs) if response: break [...] return response django/core/handlers/base.py
  • 119. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ [...] if response is None: wrapped_callback = self.make_view_atomic(callback) try: response = wrapped_callback(request, *callback_args, **callback_kwargs) except Exception as e: response = self.process_exception_by_middleware( e, request) [...] return response django/core/handlers/base.py
  • 120. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ [...] # Complain if the view returned None (a common error). if response is None: if isinstance(callback, types.FunctionType): # FBV view_name = callback.__name__ else: # CBV view_name = callback.__class__.__name__ + '.__call__' raise ValueError( "The view %s.%s didn't return an HttpResponse object. It "returned None instead." % (callback.__module__, view_na ) [...] return response django/core/handlers/base.py
  • 121. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ [...] # If the response supports deferred rendering, apply template # response middleware and then render the response elif hasattr(response, 'render') and callable(response.render): for middleware_method in self._template_response_middleware: response = middleware_method(request, response) # Complain if the template response middleware # returned None (a common error). if response is None: raise ValueError(...) [...] return response django/core/handlers/base.py
  • 122. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ [...] # If the response supports deferred rendering, apply template # response middleware and then render the response elif hasattr(response, 'render') and callable(response.render): [...] try: response = response.render() except Exception as e: response = self.process_exception_by_middleware(e, reque return response django/core/handlers/base.py
  • 123. class BaseHandler: [...] def process_exception_by_middleware(self, exception, request): """ Pass the exception to the exception middleware. If no middleware return a response for this exception, raise it. """ for middleware_method in self._exception_middleware: response = middleware_method(request, exception) if response: return response raise django/core/handlers/base.py
  • 125. class BaseHandler: [...] def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happen inside the request/response middleware. """ [...] # If the response supports deferred rendering, apply template # response middleware and then render the response elif hasattr(response, 'render') and callable(response.render): [...] try: response = response.render() except Exception as e: response = self.process_exception_by_middleware(e, reque return response django/core/handlers/base.py
  • 126. class BaseHandler: [...] def get_response(self, request): """ Return an HttpResponse object for the given HttpRequest. """ # Setup default url resolver for this thread set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) [...] return response django/core/handlers/base.py
  • 127. class BaseHandler: [...] def get_response(self, request): [...] response = self._middleware_chain(request) [...] return response django/core/handlers/base.py
  • 128. class BaseHandler: [...] def get_response(self, request): [...] response = self._middleware_chain(request) response._closable_objects.append(request) # If the exception handler returns a TemplateResponse # that has not been rendered, force it to be rendered. if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)): response = response.render() if response.status_code == 404: logger.warning( 'Not Found: %s', request.path, extra={'status_code': 404, 'request': request}) return response django/core/handlers/base.py
  • 129. class WSGIHandler(base.BaseHandler): request_class = WSGIRequest [...] def __call__(self, environ, start_response): [...] response = self.get_response(request) response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase response_headers = list(response.items()) for c in response.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) if (getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper')): response = environ['wsgi.file_wrapper'](response.file_to_str return response django/core/handlers/wsgi.py
  • 130. TIL • Django is made by humans, not wizards • Just code, no magic
  • 131. Room for contribution • Unused attributes _response_middleware and _request_middleware in BaseHandler • Wrong or misleading comments • ExceptionMiddleware does not exist
  • 133. Image credits • https://pixabay.com/en/interior-house-home- curtain-2570933/ • https://unsplash.com/photos/MEW1f-yu2KI • https://pixabay.com/en/rocket-launch-smoke-rocket-take- off-67723/ • https://pixabay.com/en/gears-cogs-machine- machinery-1236578/ • https://pixabay.com/en/balance-background-harmony- stacked-3356546/