<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文只算是本人片面之言(當然也會借鑑網路上公開資料),而且技術含量比較低,內容質量也一般,大家僅限參考即可
如果對本文看不太懂,請先閱讀後面文章,等都差不多看完再回顧來看
命令列結論:其在第二步utility.execute()函數會根據命令列引數,分發給不同的類進行處理
在manange.py裡面execute_from_command_line(sys.argv)進入關鍵程式碼
def main(): os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testDjango.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: --- execute_from_command_line(sys.argv)
2.execute_from_command_line函數裡面其範例化 ManagementUtility類然後執行utility.execute()函數 [
2.1. 此函數是專門用來分析引數的,例如python manage.py runserver
、python manage.py help
2.2 其會通過分析額外新增的引數選擇要使用的類或者函數,類或者函數對應著djangocoremanagementcommands裡面的類
def execute_from_command_line(argv=None): utility = ManagementUtility(argv) utility.execute()
3.從self.fetch_command(subcommand).run_from_argv(self.argv)[約第413行]
3.1 self.fetch_command(subcommand),這個函數返回了runserver.Command物件(可以自行深入檢視),之後執行該Command父類別裡面的run_from_argv函數
def execute(self): --- if subcommand == 'help': --- elif subcommand == 'version' or self.argv[1:] == ['--version']: sys.stdout.write(django.get_version() + 'n') elif self.argv[1:] in (['--help'], ['-h']): sys.stdout.write(self.main_help_text() + 'n') else: self.fetch_command(subcommand).run_from_argv(self.argv)
4.從run_from_argv函數self.execute(*args, **cmd_options)進入
4.1 當前類也有這個execute函數,但是由於繼承關係(此時的self也指向Command類),子類如果已經存在該函數會覆蓋執行,execute是在子類 Command類中(之後由於super還會到父類別裡面)[約第354行]
def run_from_argv(self, argv): self._called_from_command_line = True parser = self.create_parser(argv[0], argv[1]) options = parser.parse_args(argv[2:]) cmd_options = vars(options) args = cmd_options.pop('args', ()) handle_default_options(options) try: self.execute(*args, **cmd_options) except CommandError as e: ---
5.execute函數執行output = self.handle(*args, **options)[約第398行]跳進子類runserver.Command類的handle函數
5.1 此時位於Command類的父類別裡面的execute,因為super().execute(*args, **options) #繼承下來父類別
def handle(self, *args, **options): if not settings.DEBUG and not settings.ALLOWED_HOSTS: raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.') self.use_ipv6 = options['use_ipv6'] if self.use_ipv6 and not socket.has_ipv6: raise CommandError('Your Python does not support IPv6.') self._raw_ipv6 = False if not options['addrport']: --- else: --- if not self.addr: self.addr = self.default_addr_ipv6 if self.use_ipv6 else self.default_addr self._raw_ipv6 = self.use_ipv6 self.run(**options)
6.handle 函數最後一行,從 self.run(**options) 進入
def run(self, **options): use_reloader = options['use_reloader'] if use_reloader: autoreload.run_with_reloader(self.inner_run, **options) else: self.inner_run(None, **options)
7.從def inner_run(self, *args, **options)
再執行run函數
def inner_run(self, *args, **options): --- try: handler = self.get_handler(*args, **options) run(self.addr, int(self.port), handler, ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls) except OSError as e: ---
8.最後啟動服務,此時跳到django.core.servers.basehttp.py的run函數
8.1 httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
這一步特別重要,其涉及到較長的繼承關係,2.監聽-4.1這一環節會介紹到
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): server_address = (addr, port) if threading: httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) else: httpd_cls = server_cls httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) if threading: httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever()
總結流程:
解釋:WSGI開啟後,不間斷的監聽外界的請求
快速閱讀:下面寫的比較麻煩,最快了解監聽和到中介軟體前的經過就是去讀 1 、12.1 和 13
1.runserver成功開啟後,關鍵的一步是httpd.serve_forever()
,其使得進入監聽即一個死迴圈
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): --- httpd.set_app(wsgi_handler) httpd.serve_forever()
2.在serve_forever()
函數裡面執行,當ready有值時,表示有請求發來,然後進入self._handle_request_noblock()
def serve_forever(self, poll_interval=0.5): self.__is_shut_down.clear() try: with _ServerSelector() as selector: selector.register(self, selectors.EVENT_READ) while not self.__shutdown_request: ready = selector.select(poll_interval) if self.__shutdown_request: break if ready: self._handle_request_noblock() self.service_actions() ---
3.從self._handle_request_noblock()
正常請求將進入self.process_request(request, client_address)
def _handle_request_noblock(self): try: request, client_address = self.get_request() except OSError: return if self.verify_request(request, client_address): try: self.process_request(request, client_address) except Exception: self.handle_error(request, client_address) self.shutdown_request(request) except: self.shutdown_request(request) raise else: self.shutdown_request(request)
4.從self.process_request(request, client_address)
進入來到了ThreadingMixIn.process_request
4.1 此時,如果沒有搞清楚此時的self是誰,就搞不明白為什麼進入到ThreadingMixIn.process_request,而不是其它的process_request,這時候就關聯到上面提到的httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
4.2 type的用法是動態的建立類,此時httpd_cls 是一個新類,裡面分別繼承了ThreadingMixIn和server_cls對應得WSGIServer,這時就不難理解為什麼找的是ThreadingMixIn.process_request
def process_request(self, request, client_address): """Start a new thread to process the request.""" t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads if not t.daemon and self.block_on_close: if self._threads is None: self._threads = [] self._threads.append(t) t.start()
5.在def process_request(self, request, client_address)
裡面的t = threading.Thread(target = self.process_request_thread,args = (request, client_address))
實際呼叫了self.process_request_thread
,但是等t.start()
才會真正執行
def process_request_thread(self, request, client_address): """Same as in BaseServer but as a thread. In addition, exception handling is done here. """ try: self.finish_request(request, client_address) except Exception: self.handle_error(request, client_address) finally: self.shutdown_request(request)
6.從def process_request_thread(self, request, client_address)
進入,self.finish_request(request, client_address)
,繼續完成請求
6.1 這時候又需要回顧之前的程式碼,因為self.RequestHandlerClass
不是已經有的類,而是初始化的時候賦值,其值變為了某個類
6.2 這個過程就在1.啟動-8裡面的httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
,此時的httpd_cls是type動態建立的,繼承了ThreadingMixIn和server_cls對應得WSGIServer,範例化時會執行def __init__
方法,其關鍵執行了self.RequestHandlerClass = RequestHandlerClass
class BaseServer: timeout = None def __init__(self, server_address, RequestHandlerClass): """Constructor. May be extended, do not override.""" self.server_address = server_address self.RequestHandlerClass = RequestHandlerClass self.__is_shut_down = threading.Event() self.__shutdown_request = False
def finish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self) # self.RequestHandlerClass等同於self.WSGIRequestHandler
7.從self.RequestHandlerClass(request, client_address, self)
,即去WSGIRequestHandler類裡面初始化,根據一層層繼承關係,只要最老類BaseRequestHandler
有初始化方法
class BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish()
從def __init__(self, request, client_address, server):
進入self.handle()
8.1 此時的self.handle()
,根據繼承關係,其就在最小子類WSGIRequestHandler
裡面
def handle(self): self.close_connection = True self.handle_one_request() while not self.close_connection: self.handle_one_request() try: self.connection.shutdown(socket.SHUT_WR) except (AttributeError, OSError): pass
9.從def handle(self)
進入self.handle_one_request()
def handle_one_request(self): """Copy of WSGIRequestHandler.handle() but with different ServerHandler""" self.raw_requestline = self.rfile.readline(65537) if len(self.raw_requestline) > 65536: self.requestline = '' self.request_version = '' self.command = '' self.send_error(414) return if not self.parse_request(): # An error code has been sent, just exit return handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self # backpointer for logging & connection closing handler.run(self.server.get_app())
10.從def handle_one_request(self)
進入handler.run(self.server.get_app())
10.1 注意此時handler為ServerHandler範例化物件,run方法存在它的最大父類別BaseHandler裡面
10.2 此時handler.run(self.server.get_app())
執行了self.server.get_app()
,其返回django.contrib.staticfiles.handlers.StaticFilesHandler
,handler.run把其當引數傳遞了過去
def run(self, application): try: self.setup_environ() self.result = application(self.environ, self.start_response) self.finish_response() except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError): return except: ---
11.從def run(self, application)
進入self.result = application(self.environ, self.start_response)
,其中application是django.contrib.staticfiles.handlers.StaticFilesHandler
11.1 其中self.application已經初始化了是WSGIHandler
class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler): def __init__(self, application): self.application = application self.base_url = urlparse(self.get_base_url()) super().__init__() def __call__(self, environ, start_response): if not self._should_handle(get_path_info(environ)): return self.application(environ, start_response) return super().__call__(environ, start_response)
12.進入後執行def __call__(self, environ, start_response)
方法,進入return self.application(environ, start_response)
,此時self.application已經初始化了是WSGIHandler
12.1 request = self.request_class(environ)
獲取到使用者請求的url後面就開始設定runserver啟動時候載入的url; response = self.get_response(request)
獲取使用者url對應的響應準備開始往檢視轉
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) ---
13.進入response = self.get_response(request)
,結束,再下一步就要開始中介軟體的進行
def get_response(self, request): set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) response._resource_closers.append(request.close) if response.status_code >= 400: log_response( '%s: %s', response.reason_phrase, request.path, response=response, request=request, ) return response
解釋:中介軟體的執行需要聯絡著上面執行過程,這個過程是一個遞迴的過程,下面介紹的五個函數是中介軟體命名規則對應得內容
1.遞迴的進入階段:迴圈進行下面的程式碼(此程式碼位置djangocorehandlersexception.py)
1.1 此處出現process_request()
和process_response()
@wraps(get_response) def inner(request): try: response = get_response(request) # 此進入迴圈 except Exception as exc: response = response_for_exception(request, exc) return response return inner
def __call__(self, request): # Exit out to async mode, if needed if asyncio.iscoroutinefunction(self.get_response): return self.__acall__(request) response = None if hasattr(self, 'process_request'): response = self.process_request(request) # 進行中介軟體的process_request步驟 response = response or self.get_response(request) # 此進入迴圈 if hasattr(self, 'process_response'): response = self.process_response(request, response) # 此是遞迴後執行的 return response
2.遞迴的結束準備回傳:進行下面的程式碼(此程式碼位置djangocorehandlersbase.py)
2.1 此處出現process_view()
、process_template_response()
和process_exception()
進入檢視的關鍵函數:
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 is None: wrapped_callback = self.make_view_atomic(callback) # 找到檢視函數 # If it is an asynchronous view, run it in a subthread. if asyncio.iscoroutinefunction(wrapped_callback): wrapped_callback = async_to_sync(wrapped_callback) try: response = wrapped_callback(request, *callback_args, **callback_kwargs) except Exception as e: response = self.process_exception_by_middleware(e, request) if response is None: raise self.check_response(response, callback) if hasattr(response, 'render') and callable(response.render): for middleware_method in self._template_response_middleware: response = middleware_method(request, response) self.check_response( response, middleware_method, name='%s.process_template_response' % ( middleware_method.__self__.__class__.__name__, ) ) try: response = response.render() except Exception as e: response = self.process_exception_by_middleware(e, request) if response is None: raise return response
3.遞迴的結束回傳:迴圈進行下面的程式碼
@wraps(get_response) def inner(request): try: response = get_response(request) # 此進入迴圈 except Exception as exc: response = response_for_exception(request, exc) return response return inner
def __call__(self, request): # Exit out to async mode, if needed if asyncio.iscoroutinefunction(self.get_response): return self.__acall__(request) response = None if hasattr(self, 'process_request'): response = self.process_request(request) response = response or self.get_response(request) # 此進入迴圈 if hasattr(self, 'process_response'): response = self.process_response(request, response) # 進行中介軟體的process_response步驟 return response
到此這篇關於Python Django原始碼執行過程的文章就介紹到這了,更多相關Python Django原始碼執行內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45