计算机系统应用教程网站

网站首页 > 技术文章 正文

Django源代码-启动、接收、应用中间件链、路由匹配、完成请求

btikc 2024-09-16 13:03:08 技术文章 24 ℃ 0 评论
  1. if __name__ == "__main__":
  2. # 设置环境变量 export DJANGO_SETTINGS_MODULE="HelloWorld.settings"
  3. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DebugApp.settings")
  4. try:
  5. from django.core.management import execute_from_command_line
  6. except ImportError:
  7. # The above import may fail for some other reason. Ensure that the
  8. # issue is really that Django is missing to avoid masking other
  9. # exceptions on Python 2.
  10. try:
  11. import django
  12. except ImportError:
  13. raise ImportError(
  14. "Couldn't import Django. Are you sure it's installed and "
  15. "available on your PYTHONPATH environment variable? Did you "
  16. "forget to activate a virtual environment?"
  17. )
  18. raise
  19. execute_from_command_line(sys.argv)
  20. {
  21. utility = ManagementUtility(argv)
  22. {
  23. self.argv = argv or sys.argv[:]
  24. self.prog_name = os.path.basename(self.argv[0])
  25. self.settings_exception = None
  26. }
  27. utility.execute()
  28. {
  29. try:
  30. subcommand = self.argv[1]
  31. except IndexError:
  32. subcommand = 'help' # Display help if no arguments were given.
  33. # Preprocess options to extract --settings and --pythonpath.
  34. # These options could affect the commands that are available, so they
  35. # must be processed early.
  36. parser = CommandParser(None, usage="%(prog)s subcommand [options] [args]", add_help=False)
  37. parser.add_argument('--settings')
  38. parser.add_argument('--pythonpath')
  39. parser.add_argument('args', nargs='*') # catch-all
  40. try:
  41. options, args = parser.parse_known_args(self.argv[2:])
  42. handle_default_options(options)
  43. except CommandError:
  44. pass # Ignore any option errors at this point.
  45. try:
  46. # 安装的 app 列表
  47. settings.INSTALLED_APPS
  48. except ImproperlyConfigured as exc:
  49. self.settings_exception = exc
  50. if settings.configured:
  51. # Start the auto-reloading dev server even if the code is broken.
  52. # The hardcoded condition is a code smell but we can't rely on a
  53. # flag on the command class because we haven't located it yet.
  54. if subcommand == 'runserver' and '--noreload' not in self.argv:
  55. try:
  56. # 包装 django.setup 并执行
  57. autoreload.check_errors(django.setup)()
  58. except Exception:
  59. # The exception will be raised later in the child process
  60. # started by the autoreloader. Pretend it didn't happen by
  61. # loading an empty list of applications.
  62. apps.all_models = defaultdict(OrderedDict)
  63. apps.app_configs = OrderedDict()
  64. apps.apps_ready = apps.models_ready = apps.ready = True
  65. # Remove options not compatible with the built-in runserver
  66. # (e.g. options for the contrib.staticfiles' runserver).
  67. # Changes here require manually testing as described in
  68. # #27522.
  69. _parser = self.fetch_command('runserver').create_parser('django', 'runserver')
  70. _options, _args = _parser.parse_known_args(self.argv[2:])
  71. for _arg in _args:
  72. self.argv.remove(_arg)
  73. # In all other cases, django.setup() is required to succeed.
  74. else:
  75. django.setup()
  76. {
  77. # 安装应用
  78. from django.apps import apps
  79. from django.conf import settings
  80. from django.urls import set_script_prefix
  81. from django.utils.encoding import force_text
  82. from django.utils.log import configure_logging
  83. # 配置日志
  84. configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
  85. {
  86. if logging_config:
  87. # First find the logging configuration function ...
  88. logging_config_func = import_string(logging_config)
  89. logging.config.dictConfig(DEFAULT_LOGGING)
  90. # ... then invoke it with the logging settings
  91. if logging_settings:
  92. logging_config_func(logging_settings)
  93. }
  94. # 设置脚本前缀
  95. if set_prefix:
  96. set_script_prefix(
  97. '/' if settings.FORCE_SCRIPT_NAME is None else force_text(settings.FORCE_SCRIPT_NAME)
  98. )
  99. {
  100. if not prefix.endswith('/'):
  101. prefix += '/'
  102. _prefixes.value = prefix
  103. }
  104. # 填充被安装的应用 -------------------- settings.INSTALLED_APPS ------------- 1 !!!
  105. apps.populate(settings.INSTALLED_APPS)
  106. {
  107. # installed_apps === settings.INSTALLED_APPS
  108. if self.ready:
  109. return
  110. # populate() might be called by two threads in parallel on servers
  111. # that create threads before initializing the WSGI callable.
  112. with self._lock:
  113. if self.ready:
  114. return
  115. # app_config should be pristine, otherwise the code below won't
  116. # guarantee that the order matches the order in INSTALLED_APPS.
  117. if self.app_configs:
  118. raise RuntimeError("populate() isn't reentrant")
  119. # 阶段 1: 初始化 app 配置 和 导入 app 模块
  120. # Phase 1: initialize app configs and import app modules.
  121. for entry in installed_apps:
  122. # 被安装的应用,如:entry === django.contrib.sessions
  123. if isinstance(entry, AppConfig):
  124. app_config = entry
  125. else:
  126. # 创建 app_config 对象
  127. app_config = AppConfig.create(entry)
  128. {
  129. try:
  130. # 导入模块,如:django.contrib.sessions
  131. # 文件:/Library/Python/2.7/site-packages/django/contrib/sessions/__init__.py ------module------- 1.1
  132. # If import_module succeeds, entry is a path to an app module,
  133. # which may specify an app config class with default_app_config.
  134. # Otherwise, entry is a path to an app config class or an error.
  135. module = import_module(entry)
  136. except ImportError:
  137. # Track that importing as an app module failed. If importing as an
  138. # app config class fails too, we'll trigger the ImportError again.
  139. module = None
  140. mod_path, _, cls_name = entry.rpartition('.')
  141. # Raise the original exception when entry cannot be a path to an
  142. # app config class.
  143. if not mod_path:
  144. raise
  145. else:
  146. try:
  147. # 模块默认app配置
  148. # 文件 /Library/Python/2.7/site-packages/django/contrib/sessions/__init__.py 中 default_app_config ------------- 1.3
  149. # 如:default_app_config = 'django.contrib.sessions.apps.SessionsConfig'
  150. # If this works, the app module specifies an app config class.
  151. entry = module.default_app_config
  152. except AttributeError:
  153. # Otherwise, it simply uses the default app config class.
  154. return cls(entry, module)
  155. else:
  156. # 模块路径,类名
  157. # 如:entry === django.contrib.sessions.apps.SessionsConfig ------------- 1.5
  158. mod_path, _, cls_name = entry.rpartition('.')
  159. # 导入默认的app模块
  160. # mod_path === django.contrib.sessions.apps
  161. # cls_name === SessionsConfig
  162. # If we're reaching this point, we must attempt to load the app config
  163. # class located at <mod_path>.<cls_name>
  164. # 导入文件 /Library/Python/2.7/site-packages/django/contrib/sessions/apps.py 中 ------ mod ------- 1.7
  165. mod = import_module(mod_path)
  166. try:
  167. # 获取类
  168. # 文件 /Library/Python/2.7/site-packages/django/contrib/sessions/apps.py 中 SessionsConfig ------------- 1.9
  169. cls = getattr(mod, cls_name)
  170. except AttributeError:
  171. if module is None:
  172. # If importing as an app module failed, that error probably
  173. # contains the most informative traceback. Trigger it again.
  174. import_module(entry)
  175. else:
  176. raise
  177. # 类必须是 AppConfig 的子类
  178. # Check for obvious errors. (This check prevents duck typing, but
  179. # it could be removed if it became a problem in practice.)
  180. if not issubclass(cls, AppConfig):
  181. raise ImproperlyConfigured(
  182. "'%s' isn't a subclass of AppConfig." % entry)
  183. # Obtain app name here rather than in AppClass.__init__ to keep
  184. # all error checking for entries in INSTALLED_APPS in one place.
  185. try:
  186. # 类的 app 名
  187. # 如:app_name = 'django.contrib.sessions' ------------- 1.11
  188. app_name = cls.name
  189. except AttributeError:
  190. raise ImproperlyConfigured(
  191. "'%s' must supply a name attribute." % entry)
  192. # Ensure app_name points to a valid module.
  193. try:
  194. # 导入 app
  195. # 如:app_name = 'django.contrib.sessions' ------ app_module ------- 1.13
  196. app_module = import_module(app_name)
  197. except ImportError:
  198. raise ImproperlyConfigured(
  199. "Cannot import '%s'. Check that '%s.%s.name' is correct." % (
  200. app_name, mod_path, cls_name,
  201. )
  202. )
  203. # 实例化类
  204. # !!! cls === django.contrib.sessions.apps.SessionsConfig
  205. # !!! 如:app_name ==== 'django.contrib.sessions'
  206. # !!! 如:app_module ==== django.contrib.sessions
  207. # Entry is a path to an app config class.
  208. return cls(app_name, app_module)
  209. {
  210. def __init__(self, app_name, app_module):
  211. # !!! 如:app_name ==== 'django.contrib.sessions'
  212. # Full Python path to the application eg. 'django.contrib.admin'.
  213. self.name = app_name
  214. # !!! 如:app_module ==== django.contrib.sessions
  215. # Root module for the application eg. <module 'django.contrib.admin'
  216. # from 'django/contrib/admin/__init__.pyc'>.
  217. self.module = app_module
  218. # Reference to the Apps registry that holds this AppConfig. Set by the
  219. # registry when it registers the AppConfig instance.
  220. self.apps = None
  221. # The following attributes could be defined at the class level in a
  222. # subclass, hence the test-and-set pattern.
  223. # !!! 如:app_name ==== 'django.contrib.sessions'
  224. # 如:self.label === sessions
  225. # Last component of the Python path to the application eg. 'admin'.
  226. # This value must be unique across a Django project.
  227. if not hasattr(self, 'label'):
  228. self.label = app_name.rpartition(".")[2]
  229. # 转成驼峰
  230. # Human-readable name for the application eg. "Admin".
  231. if not hasattr(self, 'verbose_name'):
  232. self.verbose_name = self.label.title()
  233. # 模块路径
  234. # Filesystem path to the application directory eg.
  235. # u'/usr/lib/python2.7/dist-packages/django/contrib/admin'. Unicode on
  236. # Python 2 and a str on Python 3.
  237. if not hasattr(self, 'path'):
  238. self.path = self._path_from_module(app_module)
  239. # Module containing models eg. <module 'django.contrib.admin.models'
  240. # from 'django/contrib/admin/models.pyc'>. Set by import_models().
  241. # None if the application doesn't have a models module.
  242. self.models_module = None
  243. # Mapping of lower case model names to model classes. Initially set to
  244. # None to prevent accidental access before import_models() runs.
  245. self.models = None
  246. }
  247. }
  248. # 如:app_config === django.contrib.sessions.apps.SessionsConfig
  249. # 获取 app_config 对象的属性
  250. if app_config.label in self.app_configs:
  251. raise ImproperlyConfigured(
  252. "Application labels aren't unique, "
  253. "duplicates: %s" % app_config.label)
  254. # 保存 app_config 对象到 map 结构
  255. self.app_configs[app_config.label] = app_config
  256. # !!! 设置 app_config 对 django.apps.registry.Apps 的依赖 !!!
  257. app_config.apps = self
  258. # !!!!!!!!!!!! 至此,迭代完所有的 settings.INSTALLED_APPS !!!!!!!!!!!!
  259. # 所有应用的配置
  260. # Check for duplicate app names.
  261. counts = Counter(
  262. app_config.name for app_config in self.app_configs.values())
  263. duplicates = [
  264. name for name, count in counts.most_common() if count > 1]
  265. if duplicates: # 重复
  266. raise ImproperlyConfigured(
  267. "Application names aren't unique, "
  268. "duplicates: %s" % ", ".join(duplicates))
  269. self.apps_ready = True
  270. # 阶段2:迭代 app_config,导入 models 模块 ------------------ app_configs ------------------- 1.15
  271. # Phase 2: import models modules.
  272. for app_config in self.app_configs.values():
  273. # 如:app_config === django.contrib.sessions.apps.SessionsConfig
  274. app_config.import_models()
  275. {
  276. # 如:self.apps === django.apps.registry.Apps
  277. self.models = self.apps.all_models[self.label]
  278. # !!! 导入子模块
  279. # 如:self.module === django.contrib.sessions
  280. if module_has_submodule(self.module, MODELS_MODULE_NAME):
  281. # MODELS_MODULE_NAME === models
  282. # 如:django.contrib.sessions.models
  283. models_module_name = '%s.%s' % (self.name, MODELS_MODULE_NAME)
  284. # 导入 django.contrib.sessions.models 模块
  285. self.models_module = import_module(models_module_name)
  286. }
  287. self.clear_cache()
  288. self.models_ready = True
  289. # 阶段 3: 迭代 app_config,调用 app_config 的 ready() 方法
  290. # Phase 3: run ready() methods of app configs.
  291. for app_config in self.get_app_configs():
  292. app_config.ready()
  293. self.ready = True
  294. }
  295. }
  296. self.autocomplete()
  297. {
  298. # Don't complete if user hasn't sourced bash_completion file.
  299. if 'DJANGO_AUTO_COMPLETE' not in os.environ:
  300. return
  301. ......
  302. }
  303. if subcommand == 'help':
  304. if '--commands' in args:
  305. sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
  306. elif len(options.args) < 1:
  307. sys.stdout.write(self.main_help_text() + '\n')
  308. else:
  309. self.fetch_command(options.args[0]).print_help(self.prog_name, options.args[0])
  310. # Special-cases: We want 'django-admin --version' and
  311. # 'django-admin --help' to work, for backwards compatibility.
  312. elif subcommand == 'version' or self.argv[1:] == ['--version']:
  313. sys.stdout.write(django.get_version() + '\n')
  314. elif self.argv[1:] in (['--help'], ['-h']):
  315. sys.stdout.write(self.main_help_text() + '\n')
  316. else:
  317. #
  318. self.fetch_command(subcommand){
  319. # 获取 commands 列表
  320. # Get commands outside of try block to prevent swallowing exceptions
  321. commands = get_commands()
  322. {
  323. commands = {name: 'django.core' for name in find_commands(upath(__path__[0])){
  324. # 如:management_dir === upath(__path__[0])
  325. # 如:management_dir === /Library/Python/2.7/site-packages/django/core/management
  326. # 如:command_dir === /Library/Python/2.7/site-packages/django/core/management/commands
  327. command_dir = os.path.join(management_dir, 'commands')
  328. return [name for _, name, is_pkg in pkgutil.iter_modules([npath(command_dir)])
  329. if not is_pkg and not name.startswith('_')]
  330. }}
  331. if not settings.configured:
  332. return commands
  333. # 迭代 app_config 列表中的 commands
  334. for app_config in reversed(list(apps.get_app_configs())):
  335. path = os.path.join(app_config.path, 'management')
  336. # 查找 app_config 中的 Command 对象
  337. commands.update({name: app_config.name for name in find_commands(path)})
  338. return commands
  339. }
  340. try:
  341. # 命中 Command 对象
  342. # commands === {
  343. # 'check': 'django.core',
  344. # 'compilemessages': 'django.core',
  345. # 'runserver': 'django.core'
  346. # ...
  347. # }
  348. app_name = commands[subcommand]
  349. except KeyError:
  350. if os.environ.get('DJANGO_SETTINGS_MODULE'):
  351. # If `subcommand` is missing due to misconfigured settings, the
  352. # following line will retrigger an ImproperlyConfigured exception
  353. # (get_commands() swallows the original one) so the user is
  354. # informed about it.
  355. settings.INSTALLED_APPS
  356. else:
  357. sys.stderr.write("No Django settings specified.\n")
  358. sys.stderr.write(
  359. "Unknown command: %r\nType '%s help' for usage.\n"
  360. % (subcommand, self.prog_name)
  361. )
  362. sys.exit(1)
  363. if isinstance(app_name, BaseCommand):
  364. # If the command is already loaded, use it directly.
  365. klass = app_name
  366. else:
  367. # 实例化 Command 对象
  368. # 如: app_name === 'django.core',subcommand === 'runserver'
  369. klass = load_command_class(app_name, subcommand)
  370. {
  371. # 如: module === django.core.management.commands.runserver
  372. # 导入模块 /Library/Python/2.7/site-packages/django/core/management/commands/runserver.py
  373. module = import_module('%s.management.commands.%s' % (app_name, name))
  374. # 实例化 Command 对象
  375. # 如:module.Command() === django.core.management.commands.runserver.Command()
  376. return module.Command()
  377. }
  378. # 如: klass === django.core.management.commands.runserver.Command()
  379. return klass
  380. }
  381. .run_from_argv(self.argv) # 根据参数运行
  382. {
  383. # !!!! 执行 django.core.management.commands.runserver.Command().run_from_argv(self.argv)
  384. self._called_from_command_line = True
  385. # 创建参数解析器
  386. parser = self.create_parser(argv[0], argv[1])
  387. {
  388. parser = CommandParser(
  389. self, prog="%s %s" % (os.path.basename(prog_name), subcommand),
  390. description=self.help or None,
  391. )
  392. parser.add_argument('--version', action='version', version=self.get_version())
  393. parser.add_argument(
  394. '-v', '--verbosity', action='store', dest='verbosity', default=1,
  395. type=int, choices=[0, 1, 2, 3],
  396. help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output',
  397. )
  398. parser.add_argument(
  399. '--settings',
  400. help=(
  401. 'The Python path to a settings module, e.g. '
  402. '"myproject.settings.main". If this isn\'t provided, the '
  403. 'DJANGO_SETTINGS_MODULE environment variable will be used.'
  404. ),
  405. )
  406. parser.add_argument(
  407. '--pythonpath',
  408. help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".',
  409. )
  410. parser.add_argument('--traceback', action='store_true', help='Raise on CommandError exceptions')
  411. parser.add_argument(
  412. '--no-color', action='store_true', dest='no_color', default=False,
  413. help="Don't colorize the command output.",
  414. )
  415. self.add_arguments(parser)
  416. return parser
  417. }
  418. # 解析参数
  419. options = parser.parse_args(argv[2:])
  420. cmd_options = vars(options)
  421. # Move positional args out of options to mimic legacy optparse
  422. args = cmd_options.pop('args', ())
  423. # 处理默认选项
  424. handle_default_options(options)
  425. {
  426. if options.settings:
  427. os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
  428. if options.pythonpath:
  429. sys.path.insert(0, options.pythonpath)
  430. }
  431. # !!!执行 !!!
  432. try:
  433. self.execute(*args, **cmd_options)
  434. {
  435. # 调用子类
  436. if options['no_color']:
  437. # We rely on the environment because it's currently the only
  438. # way to reach WSGIRequestHandler. This seems an acceptable
  439. # compromise considering `runserver` runs indefinitely.
  440. os.environ[str("DJANGO_COLORS")] = str("nocolor")
  441. # 调用父类 execute - begain
  442. super(Command, self).execute(*args, **options)
  443. {
  444. if options['no_color']:
  445. self.style = no_style()
  446. self.stderr.style_func = None
  447. if options.get('stdout'):
  448. self.stdout = OutputWrapper(options['stdout'])
  449. if options.get('stderr'):
  450. self.stderr = OutputWrapper(options['stderr'], self.stderr.style_func)
  451. saved_locale = None
  452. if not self.leave_locale_alone:
  453. # Deactivate translations, because django-admin creates database
  454. # content like permissions, and those shouldn't contain any
  455. # translations.
  456. from django.utils import translation
  457. saved_locale = translation.get_language()
  458. translation.deactivate_all()
  459. try:
  460. if self.requires_system_checks and not options.get('skip_checks'):
  461. self.check()
  462. if self.requires_migrations_checks:
  463. self.check_migrations()
  464. # !!! ------ 调用子类的 handle 方法 -------
  465. output = self.handle(*args, **options)
  466. {
  467. from django.conf import settings
  468. if not settings.DEBUG and not settings.ALLOWED_HOSTS:
  469. raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.')
  470. self.use_ipv6 = options['use_ipv6']
  471. if self.use_ipv6 and not socket.has_ipv6:
  472. raise CommandError('Your Python does not support IPv6.')
  473. self._raw_ipv6 = False
  474. if not options['addrport']:
  475. self.addr = ''
  476. self.port = self.default_port
  477. else:
  478. m = re.match(naiveip_re, options['addrport'])
  479. if m is None:
  480. raise CommandError('"%s" is not a valid port number '
  481. 'or address:port pair.' % options['addrport'])
  482. self.addr, _ipv4, _ipv6, _fqdn, self.port = m.groups()
  483. if not self.port.isdigit():
  484. raise CommandError("%r is not a valid port number." % self.port)
  485. if self.addr:
  486. if _ipv6:
  487. self.addr = self.addr[1:-1]
  488. self.use_ipv6 = True
  489. self._raw_ipv6 = True
  490. elif self.use_ipv6 and not _fqdn:
  491. raise CommandError('"%s" is not a valid IPv6 address.' % self.addr)
  492. if not self.addr:
  493. self.addr = '::1' if self.use_ipv6 else '127.0.0.1'
  494. self._raw_ipv6 = self.use_ipv6
  495. # !!! ------ 调用 run() 方法 ------------
  496. self.run(**options)
  497. {
  498. # 是否使用自动加载器
  499. use_reloader = options['use_reloader']
  500. if use_reloader:
  501. # 包装 self.inner_run 函数
  502. autoreload.main(self.inner_run, None, options)
  503. {
  504. if args is None:
  505. args = ()
  506. if kwargs is None:
  507. kwargs = {}
  508. if sys.platform.startswith('java'):
  509. reloader = jython_reloader
  510. else:
  511. reloader = python_reloader
  512. wrapped_main_func = check_errors(main_func)
  513. {
  514. def wrapper(*args, **kwargs):
  515. global _exception
  516. try:
  517. # 执行 inner_run 函数
  518. fn(*args, **kwargs)
  519. except Exception:
  520. _exception = sys.exc_info()
  521. et, ev, tb = _exception
  522. if getattr(ev, 'filename', None) is None:
  523. # get the filename from the last item in the stack
  524. filename = traceback.extract_tb(tb)[-1][0]
  525. else:
  526. filename = ev.filename
  527. if filename not in _error_files:
  528. _error_files.append(filename)
  529. raise
  530. return wrapper
  531. }
  532. # 当 reloader = python_reloader
  533. reloader(wrapped_main_func, args, kwargs)
  534. {
  535. # main_func === wrapped_main_func
  536. if os.environ.get("RUN_MAIN") == "true":
  537. # !!!执行 wrapped_main_func 函数
  538. thread.start_new_thread(main_func, args, kwargs)
  539. # !!!启动监控,监控代码是否改变
  540. try:
  541. reloader_thread()
  542. {
  543. ensure_echo_on()
  544. if USE_INOTIFY:
  545. fn = inotify_code_changed
  546. else:
  547. fn = code_changed
  548. while RUN_RELOADER:
  549. # 文件改变
  550. change = fn()
  551. if change == FILE_MODIFIED:
  552. sys.exit(3) # force reload 强制重新启动,退出码=3
  553. elif change == I18N_MODIFIED:
  554. reset_translations()
  555. time.sleep(1)
  556. }
  557. except KeyboardInterrupt:
  558. pass
  559. else:
  560. try:
  561. exit_code = restart_with_reloader()
  562. {
  563. while True: # 无限循环
  564. args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions] + sys.argv
  565. new_environ = os.environ.copy()
  566. if _win and six.PY2:
  567. # Environment variables on Python 2 + Windows must be str.
  568. encoding = get_system_encoding()
  569. for key in new_environ.keys():
  570. str_key = key.decode(encoding).encode('utf-8')
  571. str_value = new_environ[key].decode(encoding).encode('utf-8')
  572. del new_environ[key]
  573. new_environ[str_key] = str_value
  574. # 设置环境
  575. new_environ["RUN_MAIN"] = 'true'
  576. # 启动子进程,并等待 exit_code
  577. exit_code = subprocess.call(args, env=new_environ)
  578. if exit_code != 3: # 退出码!=3
  579. return exit_code
  580. }
  581. if exit_code < 0:
  582. os.kill(os.getpid(), -exit_code)
  583. else:
  584. sys.exit(exit_code)
  585. except KeyboardInterrupt:
  586. pass
  587. }
  588. }
  589. else:
  590. # ------------ !!! 运行 !!! ------------
  591. self.inner_run(None, **options)
  592. {
  593. # If an exception was silenced in ManagementUtility.execute in order
  594. # to be raised in the child process, raise it now.
  595. autoreload.raise_last_exception()
  596. # 使用线程
  597. threading = options['use_threading']
  598. # 'shutdown_message' is a stealth option.
  599. shutdown_message = options.get('shutdown_message', '')
  600. quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
  601. self.stdout.write("Performing system checks...\n\n")
  602. self.check(display_num_errors=True)
  603. # Need to check migrations here, so can't use the
  604. # requires_migrations_check attribute.
  605. self.check_migrations()
  606. now = datetime.now().strftime('%B %d, %Y - %X')
  607. if six.PY2:
  608. now = now.decode(get_system_encoding())
  609. self.stdout.write(now)
  610. self.stdout.write((
  611. "Django version %(version)s, using settings %(settings)r\n"
  612. "Starting development server at %(protocol)s://%(addr)s:%(port)s/\n"
  613. "Quit the server with %(quit_command)s.\n"
  614. ) % {
  615. "version": self.get_version(),
  616. "settings": settings.SETTINGS_MODULE,
  617. "protocol": self.protocol,
  618. "addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
  619. "port": self.port,
  620. "quit_command": quit_command,
  621. })
  622. try:
  623. # handler === django.core.handlers.wsgi.WSGIHandler
  624. handler = self.get_handler(*args, **options)
  625. {
  626. return get_internal_wsgi_application()
  627. {
  628. from django.conf import settings
  629. app_path = getattr(settings, 'WSGI_APPLICATION')
  630. if app_path is None:
  631. return get_wsgi_application()
  632. {
  633. # 安装
  634. django.setup(set_prefix=False)
  635. {
  636. from django.apps import apps
  637. from django.conf import settings
  638. from django.urls import set_script_prefix
  639. from django.utils.encoding import force_text
  640. from django.utils.log import configure_logging
  641. # 日志
  642. configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
  643. if set_prefix:
  644. set_script_prefix(
  645. '/' if settings.FORCE_SCRIPT_NAME is None else force_text(settings.FORCE_SCRIPT_NAME)
  646. )
  647. # 填充 settings.INSTALLED_APPS
  648. apps.populate(settings.INSTALLED_APPS)
  649. }
  650. # 创建 django.core.handlers.wsgi.WSGIHandler 对象
  651. return WSGIHandler(){
  652. def __init__(self, *args, **kwargs):
  653. super(WSGIHandler, self).__init__(*args, **kwargs)
  654. {
  655. self._request_middleware = None
  656. self._view_middleware = None
  657. self._template_response_middleware = None
  658. self._response_middleware = None
  659. self._exception_middleware = None
  660. self._middleware_chain = None
  661. }
  662. # ------ 加载 中间件
  663. self.load_middleware()
  664. {
  665. self._request_middleware = []
  666. self._view_middleware = []
  667. self._template_response_middleware = []
  668. self._response_middleware = []
  669. self._exception_middleware = []
  670. # -------------------- 中间件 settings.MIDDLEWARE ------------- 1 !!!
  671. if settings.MIDDLEWARE is None:
  672. warnings.warn(
  673. "Old-style middleware using settings.MIDDLEWARE_CLASSES is "
  674. "deprecated. Update your middleware and use settings.MIDDLEWARE "
  675. "instead.", RemovedInDjango20Warning
  676. )
  677. handler = convert_exception_to_response(self._legacy_get_response)
  678. for middleware_path in settings.MIDDLEWARE_CLASSES:
  679. mw_class = import_string(middleware_path)
  680. try:
  681. mw_instance = mw_class()
  682. except MiddlewareNotUsed as exc:
  683. if settings.DEBUG:
  684. if six.text_type(exc):
  685. logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
  686. else:
  687. logger.debug('MiddlewareNotUsed: %r', middleware_path)
  688. continue
  689. if hasattr(mw_instance, 'process_request'):
  690. self._request_middleware.append(mw_instance.process_request)
  691. if hasattr(mw_instance, 'process_view'):
  692. self._view_middleware.append(mw_instance.process_view)
  693. if hasattr(mw_instance, 'process_template_response'):
  694. self._template_response_middleware.insert(0, mw_instance.process_template_response)
  695. if hasattr(mw_instance, 'process_response'):
  696. self._response_middleware.insert(0, mw_instance.process_response)
  697. if hasattr(mw_instance, 'process_exception'):
  698. self._exception_middleware.insert(0, mw_instance.process_exception)
  699. else:
  700. # !!! convert_exception_to_response 的用途是:包装一层 _get_response 函数,并添加捕获 _get_response 异常的代码
  701. handler = convert_exception_to_response(self._get_response)
  702. {
  703. # def convert_exception_to_response(get_response):
  704. @wraps(get_response, assigned=available_attrs(get_response))
  705. def inner(request):
  706. try:
  707. # get_response === self._get_response
  708. response = get_response(request)
  709. {
  710. # def _get_response(self, request):
  711. response = None
  712. # !!! 路由解析器
  713. if hasattr(request, 'urlconf'):
  714. urlconf = request.urlconf
  715. set_urlconf(urlconf)
  716. resolver = get_resolver(urlconf)
  717. else:
  718. resolver = get_resolver()
  719. {
  720. @lru_cache.lru_cache(maxsize=None)
  721. def get_resolver(urlconf=None):
  722. if urlconf is None:
  723. from django.conf import settings
  724. # ------------------------------------------------------------------- !!!获取 settings.ROOT_URLCONF 信息
  725. urlconf = settings.ROOT_URLCONF
  726. # urlconf === 'DebugApp.urls'
  727. return RegexURLResolver(r'^/', urlconf)
  728. {
  729. # RegexURLResolver 构造函数
  730. def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
  731. LocaleRegexProvider.__init__(self, regex)
  732. {
  733. # LocaleRegexProvider 构造函数
  734. def __init__(self, regex):
  735. # regex is either a string representing a regular expression, or a
  736. # translatable string (using ugettext_lazy) representing a regular
  737. # expression.
  738. self._regex = regex
  739. self._regex_dict = {}
  740. regex = LocaleRegexDescriptor()
  741. }
  742. # urlconf_name is the dotted Python path to the module defining
  743. # urlpatterns. It may also be an object with an urlpatterns attribute
  744. # or urlpatterns itself.
  745. self.urlconf_name = urlconf_name
  746. self.callback = None
  747. self.default_kwargs = default_kwargs or {}
  748. self.namespace = namespace
  749. self.app_name = app_name
  750. self._reverse_dict = {}
  751. self._namespace_dict = {}
  752. self._app_dict = {}
  753. # set of dotted paths to all functions and classes that are used in
  754. # urlpatterns
  755. self._callback_strs = set()
  756. self._populated = False
  757. self._local = threading.local()
  758. }
  759. }
  760. # !!! ------------------------ 匹配出路由 ------------------------ !!!
  761. resolver_match = resolver.resolve(request.path_info)
  762. {
  763. path = force_text(path) # path may be a reverse_lazy object
  764. tried = []
  765. # 匹配 '/'
  766. match = self.regex.search(path)
  767. if match:
  768. new_path = path[match.end():]
  769. # self.url_patterns = {
  770. # @cached_property
  771. # def url_patterns(self):
  772. # # urlconf_module might be a valid set of patterns, so we default to it
  773. # # 导入模块
  774. # # self.urlconf_module = {
  775. # # @cached_property
  776. # # def urlconf_module(self):
  777. # # if isinstance(self.urlconf_name, six.string_types):
  778. # # return import_module(self.urlconf_name)
  779. # # else:
  780. # # return self.urlconf_name
  781. # # }
  782. # patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  783. # try:
  784. # iter(patterns)
  785. # except TypeError:
  786. # msg = (
  787. # "The included URLconf '{name}' does not appear to have any "
  788. # "patterns in it. If you see valid patterns in the file then "
  789. # "the issue is probably caused by a circular import."
  790. # )
  791. # raise ImproperlyConfigured(msg.format(name=self.urlconf_name))
  792. # return patterns
  793. # }
  794. # 迭代所以配置的路由,进行匹配
  795. for pattern in self.url_patterns:
  796. try:
  797. # 匹配到路由
  798. sub_match = pattern.resolve(new_path)
  799. except Resolver404 as e:
  800. sub_tried = e.args[0].get('tried')
  801. if sub_tried is not None:
  802. tried.extend([pattern] + t for t in sub_tried)
  803. else:
  804. tried.append([pattern])
  805. else:
  806. if sub_match:
  807. # Merge captured arguments in match with submatch
  808. sub_match_dict = dict(match.groupdict(), **self.default_kwargs)
  809. sub_match_dict.update(sub_match.kwargs)
  810. # If there are *any* named groups, ignore all non-named groups.
  811. # Otherwise, pass all non-named arguments as positional arguments.
  812. sub_match_args = sub_match.args
  813. if not sub_match_dict:
  814. sub_match_args = match.groups() + sub_match.args
  815. return ResolverMatch(
  816. sub_match.func, # 回调函数
  817. sub_match_args, # 参数
  818. sub_match_dict,
  819. sub_match.url_name,
  820. [self.app_name] + sub_match.app_names,
  821. [self.namespace] + sub_match.namespaces,
  822. )
  823. tried.append([pattern])
  824. raise Resolver404({'tried': tried, 'path': new_path})
  825. raise Resolver404({'path': path})
  826. }
  827. # callback = 要调用的函数
  828. # callback_args = 函数参数
  829. # callback_kwargs = 函数的动态参数
  830. callback, callback_args, callback_kwargs = resolver_match
  831. request.resolver_match = resolver_match
  832. # Apply view middleware
  833. # !!! 应用 _view_middleware 类型的中间件
  834. for middleware_method in self._view_middleware:
  835. response = middleware_method(request, callback, callback_args, callback_kwargs)
  836. if response:
  837. break
  838. if response is None:
  839. # ------------------------------ wrapped_callback === 用户定义的 action
  840. wrapped_callback = self.make_view_atomic(callback)
  841. try:
  842. # ------------------------------ 执行用户定义的 action
  843. response = wrapped_callback(request, *callback_args, **callback_kwargs)
  844. except Exception as e:
  845. response = self.process_exception_by_middleware(e, request)
  846. # Complain if the view returned None (a common error).
  847. if response is None:
  848. if isinstance(callback, types.FunctionType): # FBV
  849. view_name = callback.__name__
  850. else: # CBV
  851. view_name = callback.__class__.__name__ + '.__call__'
  852. raise ValueError(
  853. "The view %s.%s didn't return an HttpResponse object. It "
  854. "returned None instead." % (callback.__module__, view_name)
  855. )
  856. # 对象 response 有 render 方法,那么进行调用 render
  857. # If the response supports deferred rendering, apply template
  858. # response middleware and then render the response
  859. elif hasattr(response, 'render') and callable(response.render):
  860. # 应用 _template_response_middleware 类型的中间件
  861. for middleware_method in self._template_response_middleware:
  862. response = middleware_method(request, response)
  863. # Complain if the template response middleware returned None (a common error).
  864. if response is None:
  865. raise ValueError(
  866. "%s.process_template_response didn't return an "
  867. "HttpResponse object. It returned None instead."
  868. % (middleware_method.__self__.__class__.__name__)
  869. )
  870. try:
  871. # 调用 render 方法
  872. response = response.render()
  873. except Exception as e:
  874. response = self.process_exception_by_middleware(e, request)
  875. return response
  876. }
  877. except Exception as exc:
  878. response = response_for_exception(request, exc)
  879. return response
  880. return inner # ------------
  881. }
  882. # handler = inner(request){ ... }
  883. # -------------------- 中间件列表 settings.MIDDLEWARE ------------- 1 !!!
  884. # 反转 中间件列表,并包装 handler
  885. for middleware_path in reversed(settings.MIDDLEWARE):
  886. middleware = import_string(middleware_path)
  887. try:
  888. # 用 middleware 包裹 handler
  889. mw_instance = middleware(handler)
  890. except MiddlewareNotUsed as exc:
  891. if settings.DEBUG:
  892. if six.text_type(exc):
  893. logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
  894. else:
  895. logger.debug('MiddlewareNotUsed: %r', middleware_path)
  896. continue
  897. if mw_instance is None:
  898. raise ImproperlyConfigured(
  899. 'Middleware factory %s returned None.' % middleware_path
  900. )
  901. if hasattr(mw_instance, 'process_view'):
  902. # process_view 中间件
  903. self._view_middleware.insert(0, mw_instance.process_view)
  904. if hasattr(mw_instance, 'process_template_response'):
  905. # process_template_response 中间件
  906. self._template_response_middleware.append(mw_instance.process_template_response)
  907. if hasattr(mw_instance, 'process_exception'):
  908. # process_exception 中间件
  909. self._exception_middleware.append(mw_instance.process_exception)
  910. # !!! convert_exception_to_response 的用途是:包装一层 mw_instance 函数,并添加捕获 mw_instance 异常的代码
  911. handler = convert_exception_to_response(mw_instance)
  912. # -------------------- middleware 链条
  913. # We only assign to this when initialization is complete as it is used
  914. # as a flag for initialization being complete.
  915. self._middleware_chain = handler
  916. }
  917. }
  918. }
  919. try:
  920. return import_string(app_path)
  921. except ImportError as e:
  922. msg = (
  923. "WSGI application '%(app_path)s' could not be loaded; "
  924. "Error importing module: '%(exception)s'" % ({
  925. 'app_path': app_path,
  926. 'exception': e,
  927. })
  928. )
  929. six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg),
  930. sys.exc_info()[2])
  931. }
  932. }
  933. # handler === django.core.handlers.wsgi.WSGIHandler
  934. # 执行
  935. # default_port = '8000'
  936. # protocol = 'http'
  937. # server_cls = django.core.servers.basehttp.WSGIServer
  938. run(self.addr, int(self.port), handler,ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
  939. {
  940. server_address = (addr, port)
  941. if threading:
  942. # 多线程的支持
  943. # 让 socketserver.ThreadingMixIn 继承,并重新 server_cls 内的方法
  944. httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, server_cls), {})
  945. else:
  946. # 单线程
  947. # httpd_cls = django.core.servers.basehttp.WSGIServer
  948. httpd_cls = server_cls
  949. httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
  950. {
  951. def __init__(self, *args, **kwargs):
  952. if kwargs.pop('ipv6', False):
  953. self.address_family = socket.AF_INET6
  954. self.allow_reuse_address = kwargs.pop('allow_reuse_address', True)
  955. super(WSGIServer, self).__init__(*args, **kwargs)
  956. {
  957. # TCPServer
  958. def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
  959. BaseServer.__init__(self, server_address, RequestHandlerClass)
  960. {
  961. def __init__(self, server_address, RequestHandlerClass):
  962. self.server_address = server_address
  963. # ------- RequestHandlerClass ------- 处理类
  964. self.RequestHandlerClass = RequestHandlerClass
  965. self.__is_shut_down = threading.Event()
  966. self.__shutdown_request = False
  967. }
  968. # 创建 socket
  969. self.socket = socket.socket(self.address_family, self.socket_type)
  970. if bind_and_activate:
  971. try:
  972. self.server_bind()
  973. {
  974. # WSGIServer
  975. def server_bind(self):
  976. HTTPServer.server_bind(self)
  977. {
  978. # HTTPServer
  979. def server_bind(self):
  980. # TCPServer
  981. SocketServer.TCPServer.server_bind(self)
  982. {
  983. def server_bind(self):
  984. if self.allow_reuse_address:
  985. self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  986. # 设置监听地址
  987. self.socket.bind(self.server_address)
  988. self.server_address = self.socket.getsockname()
  989. }
  990. host, port = self.socket.getsockname()[:2]
  991. self.server_name = socket.getfqdn(host)
  992. self.server_port = port
  993. }
  994. # WSGIServer
  995. self.setup_environ()
  996. {
  997. def setup_environ(self):
  998. # Set up base environment
  999. env = self.base_environ = {}
  1000. env['SERVER_NAME'] = self.server_name
  1001. env['GATEWAY_INTERFACE'] = 'CGI/1.1'
  1002. env['SERVER_PORT'] = str(self.server_port)
  1003. env['REMOTE_HOST']=''
  1004. env['CONTENT_LENGTH']=''
  1005. env['SCRIPT_NAME'] = ''
  1006. }
  1007. }
  1008. self.server_activate()
  1009. {
  1010. def server_activate(self):
  1011. # 设置监听队列
  1012. self.socket.listen(self.request_queue_size)
  1013. }
  1014. except:
  1015. self.server_close()
  1016. raise
  1017. }
  1018. }
  1019. if threading:
  1020. # ThreadingMixIn.daemon_threads indicates how threads will behave on an
  1021. # abrupt shutdown; like quitting the server by the user or restarting
  1022. # by the auto-reloader. True means the server will not wait for thread
  1023. # termination before it quits. This will make auto-reloader faster
  1024. # and will prevent the need to kill the server manually if a thread
  1025. # isn't terminating correctly.
  1026. httpd.daemon_threads = True
  1027. # 设置 wsgi_handler 处理器
  1028. # 如:httpd = django.core.servers.basehttp.WSGIServer
  1029. # 如:wsgi_handler == django.core.handlers.wsgi.WSGIHandler
  1030. httpd.set_app(wsgi_handler)
  1031. {
  1032. def set_app(self,application):
  1033. # 如:application == django.core.handlers.wsgi.WSGIHandler
  1034. self.application = application
  1035. }
  1036. # 执行监听
  1037. # 如:httpd = django.core.servers.basehttp.WSGIServer
  1038. httpd.serve_forever()
  1039. {
  1040. def serve_forever(self, poll_interval=0.5):
  1041. self.__is_shut_down.clear()
  1042. try:
  1043. # 死循环
  1044. while not self.__shutdown_request:
  1045. # 通过 select.select 获取连接句柄
  1046. # XXX: Consider using another file descriptor or
  1047. # connecting to the socket to wake this up instead of
  1048. # polling. Polling reduces our responsiveness to a
  1049. # shutdown request and wastes cpu at all other times.
  1050. r, w, e = _eintr_retry(select.select, [self], [], [],poll_interval)
  1051. {
  1052. def _eintr_retry(func, *args):
  1053. # restart a system call interrupted by EINTR
  1054. while True:
  1055. try:
  1056. return func(*args)
  1057. except (OSError, select.error) as e:
  1058. if e.args[0] != errno.EINTR:
  1059. raise
  1060. }
  1061. # 读句柄
  1062. if self in r:
  1063. self._handle_request_noblock()
  1064. {
  1065. def _handle_request_noblock(self):
  1066. # Handle one request, without blocking.
  1067. # I assume that select.select has returned that the socket is
  1068. # readable before this function was called, so there should be
  1069. # no risk of blocking in get_request().
  1070. try:
  1071. # 获取连接 request === connection
  1072. request, client_address = self.get_request()
  1073. {
  1074. def get_request(self):
  1075. # Get the request and client address from the socket.
  1076. # May be overridden.
  1077. return self.socket.accept()
  1078. }
  1079. except socket.error:
  1080. return
  1081. # 连接 request === connection
  1082. if self.verify_request(request, client_address):
  1083. try:
  1084. # 单进程/单线程方案,不会被重写
  1085. # 多线程方案,socketserver.ThreadingMixIn 会重写 process_request(...) 方法
  1086. # 多进程方案,socketserver.ForkingMixIn 会重写 process_request(...) 方法
  1087. # 获取连接 request === connection
  1088. self.process_request(request, client_address)
  1089. {
  1090. # 连接 request === connection
  1091. def process_request(self, request, client_address):
  1092. # Call finish_request.
  1093. # Overridden by ForkingMixIn and ThreadingMixIn.
  1094. self.finish_request(request, client_address)
  1095. {
  1096. def finish_request(self, request, client_address):
  1097. # 执行请求 request === connection
  1098. # RequestHandlerClass === django.core.servers.basehttp.WSGIRequestHandler
  1099. # Finish one request by instantiating RequestHandlerClass.
  1100. self.RequestHandlerClass(request, client_address, self)
  1101. {
  1102. # BaseRequestHandler
  1103. def __init__(self, request, client_address, server):
  1104. # request 对象 request == connection
  1105. self.request = request
  1106. self.client_address = client_address
  1107. # 如: server == django.core.servers.basehttp.WSGIServer
  1108. self.server = server
  1109. # 安装请求 === django.core.servers.basehttp.WSGIRequestHandler.setup()
  1110. self.setup()
  1111. {
  1112. # SocketServer.StreamRequestHandler
  1113. def setup(self):
  1114. # 连接 connection == request
  1115. self.connection = self.request
  1116. if self.timeout is not None:
  1117. self.connection.settimeout(self.timeout)
  1118. if self.disable_nagle_algorithm:
  1119. self.connection.setsockopt(socket.IPPROTO_TCP,
  1120. socket.TCP_NODELAY, True)
  1121. # 读句柄
  1122. self.rfile = self.connection.makefile('rb', self.rbufsize)
  1123. # 写句柄
  1124. self.wfile = self.connection.makefile('wb', self.wbufsize)
  1125. }
  1126. try:
  1127. # 处理请求 === django.core.servers.basehttp.WSGIRequestHandler.handle()
  1128. self.handle()
  1129. {
  1130. # django.core.servers.basehttp.WSGIRequestHandler.handle()
  1131. def handle(self):
  1132. # 获取 65537 行数据
  1133. # Copy of WSGIRequestHandler, but with different ServerHandler
  1134. self.raw_requestline = self.rfile.readline(65537)
  1135. if len(self.raw_requestline) > 65536:
  1136. self.requestline = ''
  1137. self.request_version = ''
  1138. self.command = ''
  1139. self.send_error(414)
  1140. return
  1141. # 解析请求
  1142. if not self.parse_request(){
  1143. self.command = None # set in case of error on the first line
  1144. self.request_version = version = self.default_request_version
  1145. self.close_connection = 1
  1146. requestline = self.raw_requestline
  1147. requestline = requestline.rstrip('\r\n')
  1148. self.requestline = requestline
  1149. words = requestline.split()
  1150. if len(words) == 3:
  1151. command, path, version = words
  1152. if version[:5] != 'HTTP/':
  1153. self.send_error(400, "Bad request version (%r)" % version)
  1154. return False
  1155. try:
  1156. # http 版本信息
  1157. base_version_number = version.split('/', 1)[1]
  1158. version_number = base_version_number.split(".")
  1159. # RFC 2145 section 3.1 says there can be only one "." and
  1160. # - major and minor numbers MUST be treated as
  1161. # separate integers;
  1162. # - HTTP/2.4 is a lower version than HTTP/2.13, which in
  1163. # turn is lower than HTTP/12.3;
  1164. # - Leading zeros MUST be ignored by recipients.
  1165. if len(version_number) != 2:
  1166. raise ValueError
  1167. version_number = int(version_number[0]), int(version_number[1])
  1168. except (ValueError, IndexError):
  1169. self.send_error(400, "Bad request version (%r)" % version)
  1170. return False
  1171. if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
  1172. self.close_connection = 0
  1173. if version_number >= (2, 0):
  1174. self.send_error(505,
  1175. "Invalid HTTP Version (%s)" % base_version_number)
  1176. return False
  1177. elif len(words) == 2:
  1178. command, path = words
  1179. self.close_connection = 1
  1180. if command != 'GET':
  1181. self.send_error(400,
  1182. "Bad HTTP/0.9 request type (%r)" % command)
  1183. return False
  1184. elif not words:
  1185. return False
  1186. else:
  1187. self.send_error(400, "Bad request syntax (%r)" % requestline)
  1188. return False
  1189. self.command, self.path, self.request_version = command, path, version
  1190. # 获取头部信息
  1191. # Examine the headers and look for a Connection directive
  1192. self.headers = self.MessageClass(self.rfile, 0)
  1193. conntype = self.headers.get('Connection', "")
  1194. if conntype.lower() == 'close':
  1195. self.close_connection = 1
  1196. elif (conntype.lower() == 'keep-alive' and
  1197. self.protocol_version >= "HTTP/1.1"):
  1198. self.close_connection = 0
  1199. return True
  1200. }: # An error code has been sent, just exit
  1201. return
  1202. # 处理请求
  1203. # handler === django.core.servers.basehttp.ServerHandler
  1204. handler = ServerHandler(
  1205. self.rfile, self.wfile, self.get_stderr(), self.get_environ()
  1206. )
  1207. {
  1208. def __init__(self,stdin,stdout,stderr,environ,
  1209. multithread=True, multiprocess=False
  1210. ):
  1211. self.stdin = stdin # 输入句柄
  1212. self.stdout = stdout # 输出句柄
  1213. self.stderr = stderr
  1214. self.base_env = environ # 环境变量
  1215. self.wsgi_multithread = multithread
  1216. self.wsgi_multiprocess = multiprocess
  1217. }
  1218. # handler.request_handler === django.core.servers.basehttp.WSGIRequestHandler
  1219. handler.request_handler = self # backpointer for logging
  1220. # !!! django.core.servers.basehttp.ServerHandler.run(self.server.get_app())
  1221. # self.server === django.core.servers.basehttp.WSGIServer
  1222. # self.server.get_app() == django.core.handlers.wsgi.WSGIHandler
  1223. handler.run(self.server.get_app())
  1224. {
  1225. def run(self, application):
  1226. # Invoke the application
  1227. # Note to self: don't move the close()! Asynchronous servers shouldn't
  1228. # call close() from finish_response(), so if you close() anywhere but
  1229. # the double-error branch here, you'll break asynchronous servers by
  1230. # prematurely closing. Async servers must return from 'run()' without
  1231. # closing if there might still be output to iterate over.
  1232. try:
  1233. # 安装环境变量
  1234. # wsgiref.handlers.BaseHandler.setup_environ()
  1235. self.setup_environ()
  1236. {
  1237. def setup_environ(self):
  1238. # Set up the environment for one request
  1239. # 拷贝系统环境变量
  1240. env = self.environ = self.os_environ.copy()
  1241. # 添加 cgi 变量
  1242. self.add_cgi_vars()
  1243. {
  1244. # SimpleHandler
  1245. def add_cgi_vars(self):
  1246. self.environ.update(self.base_env)
  1247. }
  1248. env['wsgi.input'] = self.get_stdin()
  1249. env['wsgi.errors'] = self.get_stderr()
  1250. env['wsgi.version'] = self.wsgi_version
  1251. env['wsgi.run_once'] = self.wsgi_run_once
  1252. env['wsgi.url_scheme'] = self.get_scheme()
  1253. env['wsgi.multithread'] = self.wsgi_multithread
  1254. env['wsgi.multiprocess'] = self.wsgi_multiprocess
  1255. if self.wsgi_file_wrapper is not None:
  1256. env['wsgi.file_wrapper'] = self.wsgi_file_wrapper
  1257. if self.origin_server and self.server_software:
  1258. env.setdefault('SERVER_SOFTWARE',self.server_software)
  1259. }
  1260. # 执行结果放入 self.result
  1261. # application === django.core.handlers.wsgi.WSGIHandler
  1262. self.result = application(self.environ, self.start_response)
  1263. {
  1264. # 调用
  1265. # django.core.handlers.wsgi.WSGIHandler.__call__()
  1266. def __call__(self, environ, start_response):
  1267. # 设置脚本前缀
  1268. set_script_prefix(get_script_name(environ))
  1269. signals.request_started.send(sender=self.__class__, environ=environ)
  1270. # 创建 request 对象
  1271. # request_class = django.core.handlers.wsgi.WSGIRequest
  1272. request = self.request_class(environ)
  1273. {
  1274. def __init__(self, environ):
  1275. # 获取 script_name 信息
  1276. script_name = get_script_name(environ)
  1277. # 获取 path_info 信息
  1278. path_info = get_path_info(environ)
  1279. if not path_info:
  1280. # Sometimes PATH_INFO exists, but is empty (e.g. accessing
  1281. # the SCRIPT_NAME URL without a trailing slash). We really need to
  1282. # operate as if they'd requested '/'. Not amazingly nice to force
  1283. # the path like this, but should be harmless.
  1284. path_info = '/'
  1285. self.environ = environ
  1286. self.path_info = path_info
  1287. # be careful to only replace the first slash in the path because of
  1288. # http://test/something and http://test//something being different as
  1289. # stated in http://www.ietf.org/rfc/rfc2396.txt
  1290. self.path = '%s/%s' % (script_name.rstrip('/'),
  1291. path_info.replace('/', '', 1))
  1292. self.META = environ
  1293. self.META['PATH_INFO'] = path_info
  1294. self.META['SCRIPT_NAME'] = script_name
  1295. self.method = environ['REQUEST_METHOD'].upper()
  1296. self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
  1297. if 'charset' in self.content_params:
  1298. try:
  1299. codecs.lookup(self.content_params['charset'])
  1300. except LookupError:
  1301. pass
  1302. else:
  1303. self.encoding = self.content_params['charset']
  1304. self._post_parse_error = False
  1305. try:
  1306. content_length = int(environ.get('CONTENT_LENGTH'))
  1307. except (ValueError, TypeError):
  1308. content_length = 0
  1309. self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
  1310. self._read_started = False
  1311. self.resolver_match = None
  1312. }
  1313. # 执行中间件链条,响应 response 对象
  1314. response = self.get_response(request)
  1315. {
  1316. # Setup default url resolver for this thread
  1317. set_urlconf(settings.ROOT_URLCONF)
  1318. # ------------ 传入中间件链条,并执行 ------------
  1319. response = self._middleware_chain(request)
  1320. # This block is only needed for legacy MIDDLEWARE_CLASSES; if
  1321. # MIDDLEWARE is used, self._response_middleware will be empty.
  1322. try:
  1323. # !!! 应用 _response_middleware 类的中间件
  1324. # Apply response middleware, regardless of the response
  1325. for middleware_method in self._response_middleware:
  1326. # 应用 _response_middleware 类的中间件
  1327. response = middleware_method(request, response)
  1328. # Complain if the response middleware returned None (a common error).
  1329. if response is None:
  1330. raise ValueError(
  1331. "%s.process_response didn't return an "
  1332. "HttpResponse object. It returned None instead."
  1333. % (middleware_method.__self__.__class__.__name__))
  1334. except Exception: # Any exception should be gathered and handled
  1335. signals.got_request_exception.send(sender=self.__class__, request=request)
  1336. response = self.handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  1337. response._closable_objects.append(request)
  1338. # --------- response 对象中有 render 方法 ---------
  1339. # If the exception handler returns a TemplateResponse that has not
  1340. # been rendered, force it to be rendered.
  1341. if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
  1342. response = response.render() # 调用 render 方法
  1343. # 响应状态码
  1344. if response.status_code == 404:
  1345. logger.warning(
  1346. 'Not Found: %s', request.path,
  1347. extra={'status_code': 404, 'request': request},
  1348. )
  1349. return response
  1350. }
  1351. # response._handler_class === django.core.handlers.wsgi.WSGIHandler
  1352. response._handler_class = self.__class__
  1353. # 响应状态信息
  1354. status = '%d %s' % (response.status_code, response.reason_phrase)
  1355. # 响应头
  1356. response_headers = [(str(k), str(v)) for k, v in response.items()]
  1357. # 在响应头中添加cookie信息
  1358. for c in response.cookies.values():
  1359. response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
  1360. # !!! django.core.handlers.wsgi.WSGIHandler.start_response(...)
  1361. start_response(force_str(status), response_headers)
  1362. {
  1363. def start_response(self, status, headers,exc_info=None):
  1364. # 'start_response()' callable as specified by PEP 333
  1365. if exc_info:
  1366. try:
  1367. if self.headers_sent:
  1368. # Re-raise original exception if headers sent
  1369. raise exc_info[0], exc_info[1], exc_info[2]
  1370. finally:
  1371. exc_info = None # avoid dangling circular ref
  1372. elif self.headers is not None:
  1373. raise AssertionError("Headers already set!")
  1374. assert type(status) is StringType,"Status must be a string"
  1375. assert len(status)>=4,"Status must be at least 4 characters"
  1376. assert int(status[:3]),"Status message must begin w/3-digit code"
  1377. assert status[3]==" ", "Status message must have a space after code"
  1378. if __debug__:
  1379. for name,val in headers:
  1380. assert type(name) is StringType,"Header names must be strings"
  1381. assert type(val) is StringType,"Header values must be strings"
  1382. assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
  1383. self.status = status
  1384. # !!! 响应头 headers_class === Headers
  1385. self.headers = self.headers_class(headers)
  1386. return self.write
  1387. }
  1388. if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
  1389. response = environ['wsgi.file_wrapper'](response.file_to_stream)
  1390. return response
  1391. }
  1392. # django.core.servers.basehttp.ServerHandler.finish_response()
  1393. self.finish_response()
  1394. {
  1395. def finish_response(self):
  1396. # Send any iterable data, then close self and the iterable
  1397. # Subclasses intended for use in asynchronous servers will
  1398. # want to redefine this method, such that it sets up callbacks
  1399. # in the event loop to iterate over the data, and to call
  1400. # 'self.close()' once the response is finished.
  1401. try:
  1402. if not self.result_is_file() or not self.sendfile():
  1403. # 处理执行结果 self.result
  1404. for data in self.result:
  1405. self.write(data)
  1406. {
  1407. assert type(data) is StringType,"write() argument must be string"
  1408. if not self.status:
  1409. raise AssertionError("write() before start_response()")
  1410. elif not self.headers_sent:
  1411. # Before the first output, send the stored headers
  1412. self.bytes_sent = len(data) # make sure we know content-length
  1413. self.send_headers()
  1414. {
  1415. def send_headers(self):
  1416. # Transmit headers to the client, via self._write()
  1417. self.cleanup_headers()
  1418. self.headers_sent = True
  1419. if not self.origin_server or self.client_is_modern():
  1420. self.send_preamble()
  1421. # 发送 header 数据
  1422. self._write(str(self.headers))
  1423. {
  1424. def _write(self,data):
  1425. self.stdout.write(data)
  1426. self._write = self.stdout.write
  1427. }
  1428. }
  1429. else:
  1430. self.bytes_sent += len(data)
  1431. # 发送 body 数据
  1432. # XXX check Content-Length and truncate if too many bytes written?
  1433. self._write(data)
  1434. {
  1435. def _write(self,data):
  1436. self.stdout.write(data)
  1437. self._write = self.stdout.write
  1438. }
  1439. self._flush()
  1440. }
  1441. self.finish_content()
  1442. finally:
  1443. self.close()
  1444. }
  1445. except:
  1446. try:
  1447. self.handle_error()
  1448. except:
  1449. # If we get an error handling an error, just give up already!
  1450. self.close()
  1451. raise # ...and let the actual server figure it out.
  1452. }
  1453. }
  1454. finally:
  1455. # 完成请求 === django.core.servers.basehttp.WSGIRequestHandler.finish()
  1456. self.finish()
  1457. {
  1458. # SocketServer.StreamRequestHandler
  1459. def finish(self):
  1460. if not self.wfile.closed:
  1461. try:
  1462. self.wfile.flush()
  1463. except socket.error:
  1464. # An final socket error may have occurred here, such as
  1465. # the local error ECONNABORTED.
  1466. pass
  1467. self.wfile.close()
  1468. self.rfile.close()
  1469. }
  1470. }
  1471. }
  1472. self.shutdown_request(request)
  1473. }
  1474. except:
  1475. self.handle_error(request, client_address)
  1476. self.shutdown_request(request)
  1477. }
  1478. finally:
  1479. self.__shutdown_request = False
  1480. self.__is_shut_down.set()
  1481. }
  1482. }
  1483. except socket.error as e:
  1484. # Use helpful error messages instead of ugly tracebacks.
  1485. ERRORS = {
  1486. errno.EACCES: "You don't have permission to access that port.",
  1487. errno.EADDRINUSE: "That port is already in use.",
  1488. errno.EADDRNOTAVAIL: "That IP address can't be assigned to.",
  1489. }
  1490. try:
  1491. error_text = ERRORS[e.errno]
  1492. except KeyError:
  1493. error_text = force_text(e)
  1494. self.stderr.write("Error: %s" % error_text)
  1495. # Need to use an OS exit because sys.exit doesn't work in a thread
  1496. os._exit(1)
  1497. except KeyboardInterrupt:
  1498. if shutdown_message:
  1499. self.stdout.write(shutdown_message)
  1500. sys.exit(0)
  1501. }
  1502. }
  1503. }
  1504. if output:
  1505. if self.output_transaction:
  1506. connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
  1507. output = '%s\n%s\n%s' % (
  1508. self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()),
  1509. output,
  1510. self.style.SQL_KEYWORD(connection.ops.end_transaction_sql()),
  1511. )
  1512. self.stdout.write(output)
  1513. finally:
  1514. if saved_locale is not None:
  1515. translation.activate(saved_locale)
  1516. return output
  1517. }
  1518. # 调用父类 execute - end
  1519. }
  1520. except Exception as e:
  1521. if options.traceback or not isinstance(e, CommandError):
  1522. raise
  1523. # SystemCheckError takes care of its own formatting.
  1524. if isinstance(e, SystemCheckError):
  1525. self.stderr.write(str(e), lambda x: x)
  1526. else:
  1527. self.stderr.write('%s: %s' % (e.__class__.__name__, e))
  1528. sys.exit(1)
  1529. finally:
  1530. try:
  1531. connections.close_all()
  1532. except ImproperlyConfigured:
  1533. # Ignore if connections aren't setup at this point (e.g. no
  1534. # configured settings).
  1535. pass
  1536. }
  1537. }
  1538. }

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表