欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python?Django源碼運行過程解析

 更新時間:2022年08月20日 15:30:20   作者:黑日里不滅的light  
這篇文章主要介紹了Python?Django源碼運行過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

本文只算是本人片面之言(當然也會借鑒網(wǎng)絡上公開資料),而且技術含量比較低,內容質量也一般,大家僅限參考即可

如果對本文看不太懂,請先閱讀后面文章,等都差不多看完再回顧來看

一、Django運行順序

  • WSGI會不斷監(jiān)聽客戶端發(fā)送來的請求
  • 先經(jīng)過中間件進行分析驗證處理
  • 然后經(jīng)過url分發(fā)與驗證
  • 視圖層進行處理
  • 再經(jīng)過中間件進行分析驗證處理
  • 返回響應內容

1.啟動

1.1 命令行啟動(測試服務器)

命令行結論:其在第二步utility.execute()函數(shù)會根據(jù)命令行參數(shù),分發(fā)給不同的類進行處理

在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函數(shù)里面其實例化 ManagementUtility類然后執(zhí)行utility.execute()函數(shù) [
2.1. 此函數(shù)是專門用來分析參數(shù)的,例如python manage.py runserver、python manage.py help
2.2 其會通過分析額外添加的參數(shù)選擇要使用的類或者函數(shù)類或者函數(shù)對應著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),這個函數(shù)返回了runserver.Command對象(可以自行深入查看),之后執(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)進入
4.1 當前類也有這個execute函數(shù),但是由于繼承關系(此時的self也指向Command類),子類如果已經(jīng)存在該函數(shù)會覆蓋執(zhí)行,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函數(shù)執(zhí)行output = self.handle(*args, **options)[約第398行]跳進子類runserver.Command類的handle函數(shù)
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 函數(shù)最后一行,從 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)再執(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.最后啟動服務,此時跳到django.core.servers.basehttp.py的run函數(shù)
8.1 httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) 這一步特別重要,其涉及到較長的繼承關系,2.監(jiān)聽-4.1這一環(huán)節(jié)會介紹到

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()

總結流程:

  • 解析運行 python manage.py 所提供的參數(shù),例如: help
  • 加載所有的app
  • 根據(jù)參數(shù)找到相對應的命令管理工具
  • 檢查端口ipv4檢測、ipv6檢測端口是否占用、線程檢查
  • orm對象檢查表是否創(chuàng)建
  • 最后啟動python Lib庫中的WSGIServer

2.監(jiān)聽

解釋:WSGI開啟后,不間斷的監(jiān)聽外界的請求

快速閱讀:下面寫的比較麻煩,最快了解監(jiān)聽和到中間件前的經(jīng)過就是去讀 1 、12.1 和 13

2.1 runserver(測試服務器)

1.runserver成功開啟后,關鍵的一步是httpd.serve_forever(),其使得進入監(jiān)聽即一個死循環(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í)行,當ready有值時,表示有請求發(fā)來,然后進入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,這時候就關聯(lián)到上面提到的httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
4.2 type的用法是動態(tài)的創(chuàng)建類,此時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()才會真正執(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)進入,self.finish_request(request, client_address),繼續(xù)完成請求
6.1 這時候又需要回顧之前的代碼,因為self.RequestHandlerClass不是已經(jīng)有的類,而是初始化的時候賦值,其值變?yōu)榱四硞€類
6.2 這個過程就在1.啟動-8里面的httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6),此時的httpd_cls是type動態(tài)創(chuàng)建的,繼承了ThreadingMixIn和server_cls對應得WSGIServer,實例化時會執(zhí)行def __init__方法,其關鍵執(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ù)一層層繼承關系,只要最老類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(),根據(jù)繼承關系,其就在最小子類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())執(zhí)行了self.server.get_app(),其返回django.contrib.staticfiles.handlers.StaticFilesHandler,handler.run把其當參數(shù)傳遞了過去

    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),其中applicationdjango.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.進入后執(zhí)行def __call__(self, environ, start_response)方法,進入return self.application(environ, start_response),此時self.application已經(jīng)初始化了是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

3.中間件的執(zhí)行

解釋:中間件的執(zhí)行需要聯(lián)系著上面運行過程,這個過程是一個遞歸的過程,下面介紹的五個函數(shù)中間件命名規(guī)則對應得內容

  • process_request():完成請求對象的創(chuàng)建,但用戶訪問的網(wǎng)址尚未與網(wǎng)站的路由地址匹配。
  • process_view():完成用戶訪問的網(wǎng)址與路由地址的匹配,但尚未執(zhí)行視圖函數(shù)。
  • process_exception():在執(zhí)行視圖函數(shù)的期間發(fā)生異常,比如代碼異常,主動拋出404異常等。
  • process_response():完成視圖函數(shù)的執(zhí)行,但尚未將響應內容返回瀏覽器
  • process_template_response():默認不執(zhí)行,在視圖函數(shù)完成操作后調用,除非視圖函數(shù)返回的response中有render方法(幾乎不會用,可以忽略)

1.遞歸的進入階段:循環(huá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) # 此進入循環(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) # 進行中間件的process_request步驟
        response = response or self.get_response(request) # 此進入循環(huán)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response) # 此是遞歸后執(zhí)行的
        return response

2.遞歸的結束準備回傳:進行下面的代碼(此代碼位置django\core\handlers\base.py
2.1 此處出現(xiàn)process_view()process_template_response()process_exception()

進入視圖的關鍵函數(shù):

  • callback, callback_args, callback_kwargs = self.resolve_request(request) # callback即對于視圖函數(shù)url匹配到對應的view函數(shù)
  • for middleware_method in self._view_middleware_view_middleware里面放著所有的process_view()函數(shù)(初始化時加載的), process_view()正是在該代碼下面的環(huán)節(jié)循環(huán)執(zhí)行
  • response = wrapped_callback(request, *callback_args, **callback_kwargs) 回調函數(shù)傳參,并返回試圖函數(shù)響應。
  • 沿著這個路徑連續(xù)進入兩次,就到了后面講到的as_view里面(此內容是專門視圖處理的前的關鍵步驟)
  • response = self.process_exception_by_middleware(e, request)對應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.遞歸的結束回傳:循環(huán)進行下面的代碼

        @wraps(get_response)
        def inner(request):
            try:
                response = get_response(request) # 此進入循環(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) # 此進入循環(huán)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response) # 進行中間件的process_response步驟
        return response

到此這篇關于Python Django源碼運行過程的文章就介紹到這了,更多相關Python Django源碼運行內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • python3.8與pyinstaller沖突問題的快速解決方法

    python3.8與pyinstaller沖突問題的快速解決方法

    這篇文章主要介紹了python3.8與pyinstaller沖突問題及解決方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-01-01
  • python--字典(dict)和集合(set)詳解

    python--字典(dict)和集合(set)詳解

    本文通過實例給大家介紹了python中字典和集合的知識小結,非常不錯,具有參考借鑒價值,需要的的朋友參考下吧,希望能夠給你帶來幫助
    2021-09-09
  • Pytorch:Conv2d卷積前后尺寸詳解

    Pytorch:Conv2d卷積前后尺寸詳解

    這篇文章主要介紹了Pytorch:Conv2d卷積前后尺寸,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Python3實戰(zhàn)之爬蟲抓取網(wǎng)易云音樂的熱門評論

    Python3實戰(zhàn)之爬蟲抓取網(wǎng)易云音樂的熱門評論

    這篇文章主要給大家介紹了關于Python3實戰(zhàn)之爬蟲抓取網(wǎng)易云音樂熱評的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-10-10
  • Pytorch GPU顯存充足卻顯示out of memory的解決方式

    Pytorch GPU顯存充足卻顯示out of memory的解決方式

    今天小編就為大家分享一篇Pytorch GPU顯存充足卻顯示out of memory的解決方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01
  • python將ansible配置轉為json格式實例代碼

    python將ansible配置轉為json格式實例代碼

    這篇文章主要介紹了python將ansible配置轉為json格式實例代碼的相關資料,需要的朋友可以參考下
    2017-05-05
  • Django 大文件下載實現(xiàn)過程解析

    Django 大文件下載實現(xiàn)過程解析

    這篇文章主要介紹了Django 大文件下載實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • Python生成二維碼的教程詳解

    Python生成二維碼的教程詳解

    作為一名合格的?Python?程序員,在工作中必然會用到二維碼相關操作,那如何快速的用?Python?實現(xiàn)呢?別著急,咱們這篇博客就為你解決
    2022-10-10
  • 使用python求解迷宮問題的三種實現(xiàn)方法

    使用python求解迷宮問題的三種實現(xiàn)方法

    關于迷宮問題,常見會問能不能到達某點,以及打印到達的最短路徑,下面這篇文章主要給大家介紹了關于如何使用python求解迷宮問題的三種實現(xiàn)方法,需要的朋友可以參考下
    2022-03-03
  • python使用wxpy輕松實現(xiàn)微信防撤回的方法

    python使用wxpy輕松實現(xiàn)微信防撤回的方法

    今天小編就為大家分享一篇python使用wxpy輕松實現(xiàn)微信防撤回的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-02-02

最新評論