Rumah > Artikel > pembangunan bahagian belakang > Analisis proses menjalankan kod sumber Python Django
WSGI akan terus memantau permintaan yang dihantar oleh pelanggan
melewati dahuluMiddleware menjalankan analisis dan pemprosesan pengesahan
dan kemudian melepasi pengedaran dan pengesahan url
view Layer melakukan pemprosesan
dan kemudian melepasi perisian tengah untuk analisis dan pemprosesan pengesahan
mengembalikan responsKandungan
Kesimpulan baris perintah : Ia adalah Langkah keduafungsi utiliti.execute() akan diedarkan kepada kelas yang berbeza untuk diproses mengikut parameter baris arahan
Dalam manange.py, execute_from_command_line(sys.argv) masuk kod kunci
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. Dalam fungsi execute_from_command_line, ia membuat instantiate kelas ManagementUtility dan kemudian melaksanakan fungsi utility.execute() 2.1. Fungsi ini
Digunakan khas untuk menganalisis parameter , seperti , python manage.py runserver
python manage.py help
2.2 Ia akan memilih kelas atau fungsi
untuk digunakan dengan menganalisis parameter tambahan ditambah oleh 🎜>, kelas atau fungsi sepadan dengan kelas def execute_from_command_line(argv=None):
utility = ManagementUtility(argv)
utility.execute()
dalam djangocoremanagementcommands 3. Daripada self.fetch_command(subcommand) .run_from_argv(self.argv)
3.1 self.fetch_command(subcommand), fungsi ini mengembalikan objek
runserver.Command (anda boleh lihat secara mendalam sendiri), dan kemudian laksanakan fungsi Perintahrun_from_argv ini dalam kelas induk
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 >self.execute(*args, **cmd_options) ke dalam 4.1 Kelas semasa juga mempunyai fungsi
execute ini, tetapi disebabkan oleh hubungan warisan (self pada masa ini juga menunjuk kepada Kelas perintah ), jika subkelas sudah mempunyai fungsi ini Akan menulis ganti pelaksanaan, laksanakan
berada dalam subkelas kelas Perintah (kemudian, disebabkan oleh super, ia juga akan pergi ke kelas induk ) [tentang baris 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 )[tentang baris 398] Lompat ke subkelas
mengendalikan kelas 5.1 kini terletak dalam laksanakan dalam induk kelas Kelas perintah , kerana
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 Baris terakhir fungsi, masukkan
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)
super().execute(*args, **options) #继承下来父类
dari self.run(**options)7. Laksanakan run dari Fungsi
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 Akhirnya mulakan perkhidmatan pada masa ini
django.core.servers.basehttp.pydef inner_run(self, *args, **options)
8.1 Langkah ini amat penting , yang melibatkan hubungan warisan yang panjang,
Pautan ini akan memperkenalkan proses ringkasan 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()
: httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
Analisis Jalankan parameter yang disediakan oleh python manage.py, contohnya: help
ditemui mengikut parameter Alat pengurusan arahan yang sepadan
semak port,
pengesanan ipv4, Sama ada port telah diduduki, Semakan benangormSama ada jadual semakan objek dibuat
Akhirnya mulakan WSGIServer
2. PemantauanPenjelasan: Selepas WSGI dihidupkan, pemantauan tanpa gangguan Permintaan luar
2.1 runserver (test server)1 berjaya dibuka, langkah utama ialah , yang menjadikannya memasuki pemantauan
, iaitudef run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): --- httpd.set_app(wsgi_handler) httpd.serve_forever()
httpd.serve_forever()
2 > fungsi. Apabila sedia mempunyai nilai, ini bermakna permintaan dihantar, dan kemudian masukkan 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 .Permintaan biasa daripada
akan pergi ke 4.从 5.在 6.从 7.从 从 9.从 10.从 11.从 12.进入后执行 13.进入 解释:中间件的执行需要联系着上面运行过程,这个过程是一个递归的过程,下面介绍的五个函数是中间件命名规则对应得内容 process_request():完成请求对象的创建,但用户访问的网址尚未与网站的路由地址匹配。 process_view():完成用户访问的网址与路由地址的匹配,但尚未执行视图函数。 process_exception():在执行视图函数的期间发生异常,比如代码异常,主动抛出404异常等。 process_response():完成视图函数的执行,但尚未将响应内容返回浏览器 process_template_response():默认不执行,在视图函数完成操作后调用,除非视图函数返回的response中有render方法(几乎不会用,可以忽略) 1.递归的进入阶段:循环进行下面的代码(此代码位置django\core\handlers\exception.py) 1.1 此处出现 2.递归的结束准备回传:进行下面的代码(此代码位置django\core\handlers\base.py) 进入视图的关键函数: 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 循环加载模板中间件 3.递归的结束回传:循环进行下面的代码serve_forever()
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)
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()
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)
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
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
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())
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:
---
def run(self, application)
进入self.result = application(self.environ, self.start_response)
,其中application是django.contrib.staticfiles.handlers.StaticFilesHandler
11.1 其中self.application已经初始化了是WSGIHandlerclass 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)
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)
---
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_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.1 此处出现process_view()
、process_template_response()
和process_exception()
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
@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
Atas ialah kandungan terperinci Analisis proses menjalankan kod sumber Python Django. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!