当前位置:

首页 > 编程开发 > Python Django源码运行分析指南

Python Django源码运行分析指南

Django运行顺序WSGI会不断监听客户端发送来的请求先经过中间件进行分析验证处理然后经过url分发与验证视图层进行处理再经过中间件进行分析验证处理返回响应内容1.启动1.1命令行启动(测试服务器)命令行结论:其在第二步utility.execute()函数会根据命令行参数,分发给不同的类进行处理在manange.py里面execute_from_command_line(sys.argv)进入关键代码defmain():os.environ.setdefault('DJANGO_SETTING

本文目录

    Django运行顺序

    • WSGI会不断监听客户端发送来的请求

    • 先经过中间件进行分析验证处理

    • 然后经过url分发与验证

    • 视图层进行处理

    • 再经过中间件进行分析验证处理

    • 返回响应内容

    1.启动

    1.1 命令行启动(测试服务器)

    命令行结论:其在第二步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 其会通过分析额外添加的参数选择要使用的类或者函数,类或者函数对应着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),这个函数返回了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()

    总结流程:

    • 解析运行 python manage.py 所提供的参数,例如: help

    • 加载所有的app

    • 根据参数找到相对应的命令管理工具

    • 检查端口、ipv4检测、ipv6检测、端口是否占用、线程检查

    • orm对象检查表是否创建

    • 最后启动python Lib库中的WSGIServer

    2.监听

    解释:WSGI开启后,不间断的监听外界的请求

    快速阅读:下面写的比较麻烦,最快了解监听和到中间件前的经过就是去读 1 、12.1 和 13

    2.1 runserver(测试服务器)

    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

    3.中间件的执行

    解释:中间件的执行需要联系着上面运行过程,这个过程是一个递归的过程,下面介绍的五个函数是中间件命名规则对应得内容

    • process_request():完成请求对象的创建,但用户访问的网址尚未与网站的路由地址匹配。

    • process_view():完成用户访问的网址与路由地址的匹配,但尚未执行视图函数。

    • process_exception():在执行视图函数的期间发生异常,比如代码异常,主动抛出404异常等。

    • process_response():完成视图函数的执行,但尚未将响应内容返回浏览器

    • process_template_response():默认不执行,在视图函数完成操作后调用,除非视图函数返回的response中有render方法(几乎不会用,可以忽略)

    1.递归的进入阶段:循环进行下面的代码(此代码位置django\core\handlers\exception.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.递归的结束准备回传:进行下面的代码(此代码位置django\core\handlers\base.py)
    2.1 此处出现process_view()、process_template_response()和process_exception()

    进入视图的关键函数:

    • callback, callback_args, callback_kwargs = self.resolve_request(request) # callback即对于视图函数url匹配到对应的view函数

    • for middleware_method in self._view_middleware_view_middleware里面放着所有的process_view()函数(初始化时加载的), process_view()正是在该代码下面的环节循环执行

    • response = wrapped_callback(request, *callback_args, **callback_kwargs) 回调函数传参,并返回试图函数响应。

    • 沿着这个路径连续进入两次,就到了后面讲到的as_view里面(此内容是专门视图处理的前的关键步骤)

    • response = self.process_exception_by_middleware(e, request)对应process_exception()

    • self._template_response_middleware 循环加载模板中间件

     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
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python django
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。