Python?Django源碼運(yùn)行過(guò)程解析
本文只算是本人片面之言(當(dāng)然也會(huì)借鑒網(wǎng)絡(luò)上公開(kāi)資料),而且技術(shù)含量比較低,內(nèi)容質(zhì)量也一般,大家僅限參考即可
如果對(duì)本文看不太懂,請(qǐng)先閱讀后面文章,等都差不多看完再回顧來(lái)看
一、Django運(yùn)行順序
- WSGI會(huì)不斷監(jiān)聽(tīng)客戶端發(fā)送來(lái)的請(qǐng)求
- 先經(jīng)過(guò)中間件進(jìn)行分析驗(yàn)證處理
- 然后經(jīng)過(guò)url分發(fā)與驗(yàn)證
- 視圖層進(jìn)行處理
- 再經(jīng)過(guò)中間件進(jìn)行分析驗(yàn)證處理
- 返回響應(yīng)內(nèi)容
1.啟動(dòng)
1.1 命令行啟動(dòng)(測(cè)試服務(wù)器)
命令行結(jié)論:其在第二步utility.execute()函數(shù)會(huì)根據(jù)命令行參數(shù),分發(fā)給不同的類進(jìn)行處理
在manange.py里面execute_from_command_line(sys.argv)進(jìn)入關(guān)鍵代碼
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函數(shù)里面其實(shí)例化 ManagementUtility類然后執(zhí)行utility.execute()函數(shù) [
2.1. 此函數(shù)是專門(mén)用來(lái)分析參數(shù)的,例如python manage.py runserver、python manage.py help
2.2 其會(huì)通過(guò)分析額外添加的參數(shù)選擇要使用的類或者函數(shù),類或者函數(shù)對(duì)應(yīng)著django\core\management\commands里面的類
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),這個(gè)函數(shù)返回了runserver.Command對(duì)象(可以自行深入查看),之后執(zhí)行該Command父類里面的run_from_argv函數(shù)
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函數(shù)self.execute(*args, **cmd_options)進(jìn)入
4.1 當(dāng)前類也有這個(gè)execute函數(shù),但是由于繼承關(guān)系(此時(shí)的self也指向Command類),子類如果已經(jīng)存在該函數(shù)會(huì)覆蓋執(zhí)行,execute是在子類 Command類中(之后由于super還會(huì)到父類里面)[約第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函數(shù)執(zhí)行output = self.handle(*args, **options)[約第398行]跳進(jìn)子類runserver.Command類的handle函數(shù)
5.1 此時(shí)位于Command類的父類里面的execute,因?yàn)?code>super().execute(*args, **options) #繼承下來(lái)父類
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 函數(shù)最后一行,從 self.run(**options) 進(jìn)入
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)再執(zhí)行run函數(shù)
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.最后啟動(dòng)服務(wù),此時(shí)跳到django.core.servers.basehttp.py的run函數(shù)
8.1 httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) 這一步特別重要,其涉及到較長(zhǎng)的繼承關(guān)系,2.監(jiān)聽(tīng)-4.1這一環(huán)節(jié)會(huì)介紹到
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()總結(jié)流程:
- 解析運(yùn)行 python manage.py 所提供的參數(shù),例如: help
- 加載所有的app
- 根據(jù)參數(shù)找到相對(duì)應(yīng)的命令管理工具
- 檢查端口、ipv4檢測(cè)、ipv6檢測(cè)、端口是否占用、線程檢查
- orm對(duì)象檢查表是否創(chuàng)建
- 最后啟動(dòng)python Lib庫(kù)中的WSGIServer
2.監(jiān)聽(tīng)
解釋:WSGI開(kāi)啟后,不間斷的監(jiān)聽(tīng)外界的請(qǐng)求
快速閱讀:下面寫(xiě)的比較麻煩,最快了解監(jiān)聽(tīng)和到中間件前的經(jīng)過(guò)就是去讀 1 、12.1 和 13
2.1 runserver(測(cè)試服務(wù)器)
1.runserver成功開(kāi)啟后,關(guān)鍵的一步是httpd.serve_forever(),其使得進(jìn)入監(jiān)聽(tīng)即一個(gè)死循環(huán)
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
---
httpd.set_app(wsgi_handler)
httpd.serve_forever()
2.在serve_forever()函數(shù)里面執(zhí)行,當(dāng)ready有值時(shí),表示有請(qǐng)求發(fā)來(lái),然后進(jìn)入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()正常請(qǐng)求將進(jìn)入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)進(jìn)入來(lái)到了ThreadingMixIn.process_request
4.1 此時(shí),如果沒(méi)有搞清楚此時(shí)的self是誰(shuí),就搞不明白為什么進(jìn)入到ThreadingMixIn.process_request,而不是其它的process_request,這時(shí)候就關(guān)聯(lián)到上面提到的httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
4.2 type的用法是動(dòng)態(tài)的創(chuàng)建類,此時(shí)httpd_cls 是一個(gè)新類,里面分別繼承了ThreadingMixIn和server_cls對(duì)應(yīng)得WSGIServer,這時(shí)就不難理解為什么找的是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))實(shí)際調(diào)用了self.process_request_thread,但是等t.start()才會(huì)真正執(zhí)行
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)進(jìn)入,self.finish_request(request, client_address),繼續(xù)完成請(qǐng)求
6.1 這時(shí)候又需要回顧之前的代碼,因?yàn)?code>self.RequestHandlerClass不是已經(jīng)有的類,而是初始化的時(shí)候賦值,其值變?yōu)榱四硞€(gè)類
6.2 這個(gè)過(guò)程就在1.啟動(dòng)-8里面的httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6),此時(shí)的httpd_cls是type動(dòng)態(tài)創(chuàng)建的,繼承了ThreadingMixIn和server_cls對(duì)應(yīng)得WSGIServer,實(shí)例化時(shí)會(huì)執(zhí)行def __init__方法,其關(guān)鍵執(zhí)行了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類里面初始化,根據(jù)一層層繼承關(guān)系,只要最老類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):進(jìn)入self.handle()
8.1 此時(shí)的self.handle(),根據(jù)繼承關(guān)系,其就在最小子類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)進(jìn)入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)進(jìn)入handler.run(self.server.get_app())
10.1 注意此時(shí)handler為ServerHandler實(shí)例化對(duì)象,run方法存在它的最大父類BaseHandler里面
10.2 此時(shí)handler.run(self.server.get_app())執(zhí)行了self.server.get_app(),其返回django.contrib.staticfiles.handlers.StaticFilesHandler,handler.run把其當(dāng)參數(shù)傳遞了過(guò)去
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)進(jìn)入self.result = application(self.environ, self.start_response),其中application是django.contrib.staticfiles.handlers.StaticFilesHandler
11.1 其中self.application已經(jīng)初始化了是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.進(jìn)入后執(zhí)行def __call__(self, environ, start_response)方法,進(jìn)入return self.application(environ, start_response),此時(shí)self.application已經(jīng)初始化了是WSGIHandler
12.1 request = self.request_class(environ)獲取到用戶請(qǐng)求的url后面就開(kāi)始配置runserver啟動(dòng)時(shí)候加載的url; response = self.get_response(request)獲取用戶url對(duì)應(yīng)的響應(yīng)準(zhǔn)備開(kāi)始往視圖轉(zhuǎn)
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.進(jìn)入response = self.get_response(request),結(jié)束,再下一步就要開(kāi)始中間件的進(jìn)行
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 response3.中間件的執(zhí)行
解釋:中間件的執(zhí)行需要聯(lián)系著上面運(yùn)行過(guò)程,這個(gè)過(guò)程是一個(gè)遞歸的過(guò)程,下面介紹的五個(gè)函數(shù)是中間件命名規(guī)則對(duì)應(yīng)得內(nèi)容
- process_request():完成請(qǐng)求對(duì)象的創(chuàng)建,但用戶訪問(wèn)的網(wǎng)址尚未與網(wǎng)站的路由地址匹配。
- process_view():完成用戶訪問(wèn)的網(wǎng)址與路由地址的匹配,但尚未執(zhí)行視圖函數(shù)。
- process_exception():在執(zhí)行視圖函數(shù)的期間發(fā)生異常,比如代碼異常,主動(dòng)拋出404異常等。
- process_response():完成視圖函數(shù)的執(zhí)行,但尚未將響應(yīng)內(nèi)容返回瀏覽器
- process_template_response():默認(rèn)不執(zhí)行,在視圖函數(shù)完成操作后調(diào)用,除非視圖函數(shù)返回的response中有render方法(幾乎不會(huì)用,可以忽略)
1.遞歸的進(jìn)入階段:循環(huán)進(jìn)行下面的代碼(此代碼位置django\core\handlers\exception.py)
1.1 此處出現(xiàn)process_request()和process_response()
@wraps(get_response)
def inner(request):
try:
response = get_response(request) # 此進(jìn)入循環(huán)
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) # 進(jìn)行中間件的process_request步驟
response = response or self.get_response(request) # 此進(jìn)入循環(huán)
if hasattr(self, 'process_response'):
response = self.process_response(request, response) # 此是遞歸后執(zhí)行的
return response
2.遞歸的結(jié)束準(zhǔn)備回傳:進(jìn)行下面的代碼(此代碼位置django\core\handlers\base.py)
2.1 此處出現(xiàn)process_view()、process_template_response()和process_exception()
進(jìn)入視圖的關(guān)鍵函數(shù):
- callback, callback_args, callback_kwargs = self.resolve_request(request) # callback即對(duì)于視圖函數(shù)url匹配到對(duì)應(yīng)的view函數(shù)
- for middleware_method in self._view_middleware_view_middleware里面放著所有的process_view()函數(shù)(初始化時(shí)加載的), process_view()正是在該代碼下面的環(huán)節(jié)循環(huán)執(zhí)行
- response = wrapped_callback(request, *callback_args, **callback_kwargs) 回調(diào)函數(shù)傳參,并返回試圖函數(shù)響應(yīng)。
- 沿著這個(gè)路徑連續(xù)進(jìn)入兩次,就到了后面講到的as_view里面(此內(nèi)容是專門(mén)視圖處理的前的關(guān)鍵步驟)
- response = self.process_exception_by_middleware(e, request)對(duì)應(yīng)process_exception()
- self._template_response_middleware 循環(huán)加載模板中間件
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) # 找到視圖函數(shù)
# 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.遞歸的結(jié)束回傳:循環(huán)進(jìn)行下面的代碼
@wraps(get_response)
def inner(request):
try:
response = get_response(request) # 此進(jìn)入循環(huán)
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) # 此進(jìn)入循環(huán)
if hasattr(self, 'process_response'):
response = self.process_response(request, response) # 進(jìn)行中間件的process_response步驟
return response
到此這篇關(guān)于Python Django源碼運(yùn)行過(guò)程的文章就介紹到這了,更多相關(guān)Python Django源碼運(yùn)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python3.8與pyinstaller沖突問(wèn)題的快速解決方法
這篇文章主要介紹了python3.8與pyinstaller沖突問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
Python3實(shí)戰(zhàn)之爬蟲(chóng)抓取網(wǎng)易云音樂(lè)的熱門(mén)評(píng)論
這篇文章主要給大家介紹了關(guān)于Python3實(shí)戰(zhàn)之爬蟲(chóng)抓取網(wǎng)易云音樂(lè)熱評(píng)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
Pytorch GPU顯存充足卻顯示out of memory的解決方式
今天小編就為大家分享一篇Pytorch GPU顯存充足卻顯示out of memory的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
python將ansible配置轉(zhuǎn)為json格式實(shí)例代碼
這篇文章主要介紹了python將ansible配置轉(zhuǎn)為json格式實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05
Django 大文件下載實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Django 大文件下載實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
使用python求解迷宮問(wèn)題的三種實(shí)現(xiàn)方法
關(guān)于迷宮問(wèn)題,常見(jiàn)會(huì)問(wèn)能不能到達(dá)某點(diǎn),以及打印到達(dá)的最短路徑,下面這篇文章主要給大家介紹了關(guān)于如何使用python求解迷宮問(wèn)題的三種實(shí)現(xiàn)方法,需要的朋友可以參考下2022-03-03
python使用wxpy輕松實(shí)現(xiàn)微信防撤回的方法
今天小編就為大家分享一篇python使用wxpy輕松實(shí)現(xiàn)微信防撤回的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-02-02

