您现在的位置是:网站首页> 编程资料编程资料

Python Django源码运行过程解析_python_

2023-05-26 414人已围观

简介 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 runserverpython 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(
                
                

-六神源码网