您现在的位置是:网站首页> 编程资料编程资料
Python Django源码运行过程解析_python_
2023-05-26
415人已围观
简介 Python Django源码运行过程解析_python_
本文只算是本人片面之言(当然也会借鉴网络上公开资料),而且技术含量比较低,内容质量也一般,大家仅限参考即可
如果对本文看不太懂,请先阅读后面文章,等都差不多看完再回顾来看
一、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(
相关内容
- Python可视化程序调用流程解析_python_
- python 文件读写和数据清洗_python_
- Python pywin32实现word与Excel的处理_python_
- python中list列表复制的几种方法(赋值、切片、copy(),deepcopy())_python_
- Python 实操显示数据图表并固定时间长度_python_
- python爬虫beautiful soup的使用方式_python_
- python3 requests中文乱码之压缩格式问题解析_python_
- python math模块使用方法介绍_python_
- Python计算标准差之numpy.std和torch.std的区别_python_
- Python 读取 Word 文档操作_python_
点击排行
本栏推荐
