Python|Python Django源码运行过程解析
目录
- 一、Django运行顺序
- 1.启动
- 1.1 命令行启动(测试服务器)
- 2.监听
- 2.1 runserver(测试服务器)
- 3.中间件的执行
如果对本文看不太懂,请先阅读后面文章,等都差不多看完再回顾来看
一、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_lineexcept 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 = Trueparser = 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 = Falseif not options['addrport']:---else:---if not self.addr:self.addr = self.default_addr_ipv6 if self.use_ipv6 else self.default_addrself._raw_ipv6 = self.use_ipv6self.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_clshttpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)if threading:httpd.daemon_threads = Truehttpd.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:breakif 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:returnif 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)raiseelse:self.shutdown_request(request)
4.从
self.process_request(request, client_address)
进入来到了ThreadingMixIn.process_request4.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_threadsif 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 = Nonedef __init__(self, server_address, RequestHandlerClass):"""Constructor.May be extended, do not override."""self.server_address = server_addressself.RequestHandlerClass = RequestHandlerClassself.__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 = requestself.client_address = client_addressself.server = serverself.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 = Trueself.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)returnif not self.parse_request():# An error code has been sent, just exitreturnhandler = ServerHandler(self.rfile, self.wfile, self.get_stderr(), self.get_environ())handler.request_handler = self# backpointer for logging & connection closinghandler.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):returnexcept:---
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 = applicationself.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已经初始化了是WSGIHandler12.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方法(几乎不会用,可以忽略)
【Python|Python Django源码运行过程解析】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 responsereturn inner
def __call__(self, request):# Exit out to async mode, if neededif asyncio.iscoroutinefunction(self.get_response):return self.__acall__(request)response = Noneif 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 = Nonecallback, 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:breakif 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:raiseself.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:raisereturn response
3.递归的结束回传:循环进行下面的代码
@wraps(get_response)def inner(request):try:response = get_response(request) # 此进入循环except Exception as exc:response = response_for_exception(request, exc)return responsereturn inner
def __call__(self, request):# Exit out to async mode, if neededif asyncio.iscoroutinefunction(self.get_response):return self.__acall__(request)response = Noneif 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
到此这篇关于Python Django源码运行过程的文章就介绍到这了,更多相关Python Django源码运行内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- 2022年8月刷爆的Java面试八股文来了,包含中级-高级-源码面试题解析,内涵25个专题,200+面试题解析
- python|OpenCV中图像形态学操作
- fpga开发|基于 FPGA 使用 Verilog 实现 DS18B20 温度采集以及数码管显示项目源码
- Mybatis|Mybatis 插件使用及源码分析
- 机器学习|吴恩达机器学习作业一(利用多元线性回归模型实现房价预测(python实现))
- Python自动化办公之PDF拆分
- Python|Python网络编程—TCP客户端和服务器
- #|Python网络编程之TCP编程
- python|Python实现一个简单的HTTP服务器(GET/POST)
- python聚类算法程序实现图像处理_K-means聚类算法及python代码实现