Django Launch and Request Flow
Basic information
- Django version: 2.1
Django launch flow
PEP 3333
- PEP 3333
- 角色
- Web Server/Gatway
- 呼叫Application/Framework的callable實例,並傳入environ, start_response兩個參數
- environ:
- Type: Dict
- 當前環境的上下文管理變數,為Dict type
- start_response:
- Type: Callable
- 接收两个参数, 分别是响应的状态码
- 返回Response Body
- environ:
- 呼叫Application/Framework的callable實例,並傳入environ, start_response兩個參數
- Application/Framework
- 需要實作一個callble的實例,包含函數、方法、類,或帶有__call__的方法
- Middleware
- 對上級的Web Server或Middleware扮演Application的角色
- 對下級的Application或Middleware扮演Server的角色
- Web Server/Gatway
Interaction Diagram
Explanation
- manage.py runserver
- 此為每個Django Application的入口,在建立Django Project時,會自動產生
- 重點步驟
- 指定DJANGO_SETTINGS_MODUL,此為重要配置,Django Project相關配置皆使用該文件設定
- 使用django.core.management的execute_from_command_line將參數傳遞至Django內部
- management @django/core/management/init.py
- 初始化ManagementUtility,並呼叫其execute方法
- utility: ManagementUtility @django/core/management/init.py
- execute方法
- 判斷argv中的輸入,執行對應的動作,現在參數為”runserver”
- self.fetch_command(subcommand).run_from_argv(self.argv)
- fetch_command(subcommand)取得Command
- execute方法
Command @django/core/management/commands/runserver.py
- run_from_argv(self.argv)
- run_from_argv在Command的父類 @django/core/management/base.py #BaseCommand
- execute(self, args, *options) #BaseCommand
- handle(self, args, *options) #Command
- run(self, **options) #Command
inner_run(self, args, *options) #Command
123456789def inner_run(self, *args, **options):# ...try:# 取得WSGIHandler @django/core/handlers/wsgi.pyhandler = self.get_handler(*args, **options)run(self.addr, int(self.port), handler,ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)except socket.error as e:# ...
- run_from_argv(self.argv)
run @django/core/servers/basehttp.py
12345678910def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):# ...# httpd_cls是WSGIServer @django/core/servers/basehttp.py# WSGIRequestHandler @django/core/servers/basehttp.py# WSGIRequestHandler最中會指定給WSGIServer的父類BaseServer的self.RequestHandlerClass變數httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)# ...# wsgi_handler由上一步傳入的WSGIHandler @django/core/handlers/wsgi.pyhttpd.set_app(wsgi_handler)httpd.serve_forever()httpd.set_app
12def set_app(self,application):self.application = application- application會在之後處理HTTP request時候使用
- httpd.serve_forever
- 父類 BaseServer中的方法
- 不斷接收與處理HTTP request,直到接收到shutdown信號
Djagno with PEP3333
- Web Server/Gatway <-> WSGIServer
- Application/Framework <-> WSGIHandler
Django Request and Response Flow
Interaction Diagram
Explanation
HTTP request
- 當有HTTP/HTTPS request到達時,WSGIServer的serve_forever方法中的which loop會透過_handle_request_noblock處理request,之後調用內部的process_request,finish_request方法
上述方法皆在WSGIServer的父類BaseServer中
123def finish_request(self, request, client_address):"""Finish one request by instantiating RequestHandlerClass."""self.RequestHandlerClass(request, client_address, self)
RequestHandlerClass
- 在finish_request方法中調用了self.RequestHandlerClass
- RequestHandlerClass變量是run @django/core/servers/basehttp.py時傳入,Class為WSGIRequestHandler @django/core/servers/basehttp.py
WSGIRequestHandler在其父類BaseRequestHandler的int方法中呼叫handle方法
1234567class BaseRequestHandler:def __init__(self, request, client_address, server):# ...try:self.handle()finally:# ...handle方法實作在WSGIRequestHandler內,並呼叫自身的handle_one_request
12345678class WSGIRequestHandler(simple_server.WSGIRequestHandler):def handle(self):# ...handler = ServerHandler(self.rfile, self.wfile, self.get_stderr(), self.get_environ())handler.request_handler = self # backpointer for logginghandler.run(self.server.get_app())
ServerHandler
run方法在其父類BaseHandler中
1234567891011121314151617class BaseHandler:def run(self, application):# ...try:self.setup_environ()self.result = application(self.environ, self.start_response)self.finish_response()except:# ...def finish_response(self):try:if not self.result_is_file() or not self.sendfile():for data in self.result:self.write(data)self.finish_content()finally:self.close()application(self.environ, self.start_response)
- application為run方法的參數,使用WSGIRequestHandler中的self.server.get_app()取得
- self.server.get_app()
- self.server是在WSGIRequestHandler初始化時,其父類的參數
- 參數是在WSGIServer中,使用self傳入,故self.server就是WSGIServer object
- get_app方法對應WSGIServer的set_app方法,是在run @django/core/servers/basehttp.py 傳入,對應的是WSGIHandler
- 故self.server.get_app()回傳的就是WSGIHandler class
WSGIHandler @django/core/handlers/wsgi.py
- 在application(self.environ, self.start_response)會呼叫init
- 載入middleware
在finish_response方法中的self.result會呼叫WSGIHandler的call
- 開始處理request,根據順序走訪middleware與開發者定義View,最終回傳response
- call是根據PEP3333的Application規定實作,讓WSGIHandler成為callable,並且接收environ, start_response 2個參數
1234567891011121314151617181920212223242526272829class WSGIHandler(base.BaseHandler):request_class = WSGIRequestdef __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.load_middleware()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)# ...return responseclass BaseHandler:def get_response(self, request):"""Return an HttpResponse object for the given HttpRequest."""# Setup default url resolver for this threadset_urlconf(settings.ROOT_URLCONF)response = self._middleware_chain(request)response._closable_objects.append(request)if response.status_code >= 400:log_response('%s: %s', response.reason_phrase, request.path,response=response,request=request,)return response
- 在application(self.environ, self.start_response)會呼叫init