Home > Article > Backend Development > Analyze the running process of Python Django source code
WSGI will continue to monitor requests sent from the client
passes through## first #MiddlewarePerform analysis and verification processing
url distribution and verification
view Layer is processed
middleware for analysis and verification processing
responseContent
Command line conclusion: It is The second step utility.execute() function will be distributed to different classes for processing according to the command line parameters
In manage.py, execute_from_command_line(sys.argv) enters the key codedef 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.In the execute_from_command_line function, its
instantiation ManagementUtility class then executes the utility.execute() function [2.1. This function is
specially used to analyze parameters, such as python manage.py runserver,
python manage.py help2.2 which will be additionally added by analyzing
The parameters select the class or function to be used, the class or function corresponds to the class
def execute_from_command_line(argv=None): utility = ManagementUtility(argv) utility.execute()in django\core\management\commands 3.From
self.fetch_command(subcommand).run_from_argv(self.argv)[about line 413]3.1
self.fetch_command(subcommand), this function The runserver.Command object is returned (you can view it in depth by yourself), and then the run_from_argv function in the Command parent class is executed
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. Enter
run_from_argv function self.execute(*args, **cmd_options) to enter 4.1 The current class also has this
execute function, but due to the inheritance relationship (this self also points to the Command class). If the subclass already exists, the function will overwrite the execution. execute is in the subclass Command class (later due to super Will also go to the parent class) [about line 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.executeFunction executionoutput = self.handle(*args, * *options)[About line 398] Jump into the handle function of the subclass runserver.Command class5.1 is now located in the
Command class execute in the parent class, because super().execute(*args, **options) #inherited from the parent class
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 The last line of the function, from self.run(**options) Enter
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. From
def inner_run(self, *args, \*\*options )Execute the
run function again
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. Finally start the service and jump to the run function# of
django.core.servers.basehttp.py ##8.1 httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
This step is particularly important, as it involves a long inheritance relationship, 2. Listening-4.1
This link will introduce 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()
Summary process:
,ipv4 detection,ipv6 detection,whether the port is occupied,thread check
Object check table is created
#2. Monitoring
the process before listening and reaching the middleware
is to read1, 12.1 and 132.1 runserver (test server)
1 After .runserver is successfully opened, the key step ismonitoring, which is an
infinite loop
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): --- httpd.set_app(wsgi_handler) httpd.serve_forever()2 .Executed in the serve_forever() function. When
ready has a value, it means that a request has been sent, and then enters
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. From
self._handle_request_noblock()Normal request will enter 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
解释:中间件的执行需要联系着上面运行过程,这个过程是一个递归的过程,下面介绍的五个函数是中间件命名规则对应得内容
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
The above is the detailed content of Analyze the running process of Python Django source code. For more information, please follow other related articles on the PHP Chinese website!