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

if __name__ == "__main__":
    # 设置环境变量 export DJANGO_SETTINGS_MODULE="HelloWorld.settings"
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DebugApp.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError:
        # The above import may fail for some other reason. Ensure that the
        # issue is really that Django is missing to avoid masking other
        # exceptions on Python 2.
        try:
            import django
        except ImportError:
            raise ImportError(
                "Couldn't import Django. Are you sure it's installed and "
                "available on your PYTHONPATH environment variable? Did you "
                "forget to activate a virtual environment?"
            )
        raise
    execute_from_command_line(sys.argv)
    {
        utility = ManagementUtility(argv)
        {
            self.argv = argv or sys.argv[:]
            self.prog_name = os.path.basename(self.argv[0])
            self.settings_exception = None
        }
        
        utility.execute()
        {
            try:
                subcommand = self.argv[1]
            except IndexError:
                subcommand = 'help'  # Display help if no arguments were given.

            # Preprocess options to extract --settings and --pythonpath.
            # These options could affect the commands that are available, so they
            # must be processed early.
            parser = CommandParser(None, usage="%(prog)s subcommand [options] [args]", add_help=False)
            parser.add_argument('--settings')
            parser.add_argument('--pythonpath')
            parser.add_argument('args', nargs='*')  # catch-all
            try:
                options, args = parser.parse_known_args(self.argv[2:])
                handle_default_options(options)
            except CommandError:
                pass  # Ignore any option errors at this point.

            try:
                # 安装的 app 列表
                settings.INSTALLED_APPS
            except ImproperlyConfigured as exc:
                self.settings_exception = exc

            if settings.configured:
                # Start the auto-reloading dev server even if the code is broken.
                # The hardcoded condition is a code smell but we can't rely on a
                # flag on the command class because we haven't located it yet.
                if subcommand == 'runserver' and '--noreload' not in self.argv:
                    try:
                        # 包装 django.setup 并执行
                        autoreload.check_errors(django.setup)()
                    except Exception:
                        # The exception will be raised later in the child process
                        # started by the autoreloader. Pretend it didn't happen by
                        # loading an empty list of applications.
                        apps.all_models = defaultdict(OrderedDict)
                        apps.app_configs = OrderedDict()
                        apps.apps_ready = apps.models_ready = apps.ready = True

                        # Remove options not compatible with the built-in runserver
                        # (e.g. options for the contrib.staticfiles' runserver).
                        # Changes here require manually testing as described in
                        # #27522.
                        _parser = self.fetch_command('runserver').create_parser('django', 'runserver')
                        _options, _args = _parser.parse_known_args(self.argv[2:])
                        for _arg in _args:
                            self.argv.remove(_arg)

                # In all other cases, django.setup() is required to succeed.
                else:
                    django.setup()
                    {
                        # 安装应用
                        from django.apps import apps
                        from django.conf import settings
                        from django.urls import set_script_prefix
                        from django.utils.encoding import force_text
                        from django.utils.log import configure_logging

                        # 配置日志
                        configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
                        {
                            if logging_config:
                                # First find the logging configuration function ...
                                logging_config_func = import_string(logging_config)

                                logging.config.dictConfig(DEFAULT_LOGGING)

                                # ... then invoke it with the logging settings
                                if logging_settings:
                                    logging_config_func(logging_settings)
                        }

                        # 设置脚本前缀
                        if set_prefix:
                            set_script_prefix(
                                '/' if settings.FORCE_SCRIPT_NAME is None else force_text(settings.FORCE_SCRIPT_NAME)
                            )
                            {
                                    if not prefix.endswith('/'):
                                        prefix += '/'
                                    _prefixes.value = prefix
                            }

                        # 填充被安装的应用 -------------------- settings.INSTALLED_APPS ------------- 1 !!!
                        apps.populate(settings.INSTALLED_APPS)
                        {
                            # installed_apps === settings.INSTALLED_APPS

                            if self.ready:
                                return

                            # populate() might be called by two threads in parallel on servers
                            # that create threads before initializing the WSGI callable.
                            with self._lock:
                                if self.ready:
                                    return

                                # app_config should be pristine, otherwise the code below won't
                                # guarantee that the order matches the order in INSTALLED_APPS.
                                if self.app_configs:
                                    raise RuntimeError("populate() isn't reentrant")

                                # 阶段 1: 初始化 app 配置 和 导入 app 模块
                                # Phase 1: initialize app configs and import app modules.
                                for entry in installed_apps:
                                    # 被安装的应用,如:entry === django.contrib.sessions
                                    if isinstance(entry, AppConfig):
                                        app_config = entry
                                    else:
                                        # 创建 app_config 对象
                                        app_config = AppConfig.create(entry)
                                        {
                                            try:
                                                # 导入模块,如:django.contrib.sessions
                                                # 文件:/Library/Python/2.7/site-packages/django/contrib/sessions/__init__.py ------module------- 1.1
                                                # If import_module succeeds, entry is a path to an app module,
                                                # which may specify an app config class with default_app_config.
                                                # Otherwise, entry is a path to an app config class or an error.
                                                module = import_module(entry)

                                            except ImportError:
                                                # Track that importing as an app module failed. If importing as an
                                                # app config class fails too, we'll trigger the ImportError again.
                                                module = None

                                                mod_path, _, cls_name = entry.rpartition('.')

                                                # Raise the original exception when entry cannot be a path to an
                                                # app config class.
                                                if not mod_path:
                                                    raise

                                            else:
                                                try:
                                                    # 模块默认app配置
                                                    # 文件 /Library/Python/2.7/site-packages/django/contrib/sessions/__init__.py 中 default_app_config ------------- 1.3
                                                    # 如:default_app_config = 'django.contrib.sessions.apps.SessionsConfig'
                                                    # If this works, the app module specifies an app config class.
                                                    entry = module.default_app_config
                                                except AttributeError:
                                                    # Otherwise, it simply uses the default app config class.
                                                    return cls(entry, module)
                                                else:
                                                    # 模块路径,类名
                                                    # 如:entry === django.contrib.sessions.apps.SessionsConfig  ------------- 1.5
                                                    mod_path, _, cls_name = entry.rpartition('.')

                                            # 导入默认的app模块
                                            # mod_path === django.contrib.sessions.apps
                                            # cls_name === SessionsConfig
                                            # If we're reaching this point, we must attempt to load the app config
                                            # class located at <mod_path>.<cls_name>
                                            # 导入文件 /Library/Python/2.7/site-packages/django/contrib/sessions/apps.py 中 ------ mod ------- 1.7
                                            mod = import_module(mod_path)
                                            try:
                                                # 获取类
                                                # 文件 /Library/Python/2.7/site-packages/django/contrib/sessions/apps.py 中 SessionsConfig ------------- 1.9
                                                cls = getattr(mod, cls_name)
                                            except AttributeError:
                                                if module is None:
                                                    # If importing as an app module failed, that error probably
                                                    # contains the most informative traceback. Trigger it again.
                                                    import_module(entry)
                                                else:
                                                    raise

                                            # 类必须是 AppConfig 的子类
                                            # Check for obvious errors. (This check prevents duck typing, but
                                            # it could be removed if it became a problem in practice.)
                                            if not issubclass(cls, AppConfig):
                                                raise ImproperlyConfigured(
                                                    "'%s' isn't a subclass of AppConfig." % entry)

                                            # Obtain app name here rather than in AppClass.__init__ to keep
                                            # all error checking for entries in INSTALLED_APPS in one place.
                                            try:
                                                # 类的 app 名
                                                # 如:app_name = 'django.contrib.sessions' ------------- 1.11
                                                app_name = cls.name
                                            except AttributeError:
                                                raise ImproperlyConfigured(
                                                    "'%s' must supply a name attribute." % entry)

                                            # Ensure app_name points to a valid module.
                                            try:
                                                # 导入 app
                                                # 如:app_name = 'django.contrib.sessions' ------ app_module ------- 1.13
                                                app_module = import_module(app_name)
                                            except ImportError:
                                                raise ImproperlyConfigured(
                                                    "Cannot import '%s'. Check that '%s.%s.name' is correct." % (
                                                        app_name, mod_path, cls_name,
                                                    )
                                                )
                                            # 实例化类
                                            # !!! cls === django.contrib.sessions.apps.SessionsConfig
                                            # !!! 如:app_name ==== 'django.contrib.sessions'
                                            # !!! 如:app_module ==== django.contrib.sessions
                                            # Entry is a path to an app config class.
                                            return cls(app_name, app_module)
                                            {
                                                def __init__(self, app_name, app_module):

                                                    # !!! 如:app_name ==== 'django.contrib.sessions'
                                                    # Full Python path to the application eg. 'django.contrib.admin'.
                                                    self.name = app_name

                                                    # !!! 如:app_module ==== django.contrib.sessions
                                                    # Root module for the application eg. <module 'django.contrib.admin'
                                                    # from 'django/contrib/admin/__init__.pyc'>.
                                                    self.module = app_module

                                                    # Reference to the Apps registry that holds this AppConfig. Set by the
                                                    # registry when it registers the AppConfig instance.
                                                    self.apps = None

                                                    # The following attributes could be defined at the class level in a
                                                    # subclass, hence the test-and-set pattern.

                                                    # !!! 如:app_name ==== 'django.contrib.sessions'
                                                    # 如:self.label === sessions
                                                    # Last component of the Python path to the application eg. 'admin'.
                                                    # This value must be unique across a Django project.
                                                    if not hasattr(self, 'label'):
                                                        self.label = app_name.rpartition(".")[2]

                                                    # 转成驼峰
                                                    # Human-readable name for the application eg. "Admin".
                                                    if not hasattr(self, 'verbose_name'):
                                                        self.verbose_name = self.label.title()

                                                    # 模块路径
                                                    # Filesystem path to the application directory eg.
                                                    # u'/usr/lib/python2.7/dist-packages/django/contrib/admin'. Unicode on
                                                    # Python 2 and a str on Python 3.
                                                    if not hasattr(self, 'path'):
                                                        self.path = self._path_from_module(app_module)

                                                    # Module containing models eg. <module 'django.contrib.admin.models'
                                                    # from 'django/contrib/admin/models.pyc'>. Set by import_models().
                                                    # None if the application doesn't have a models module.
                                                    self.models_module = None

                                                    # Mapping of lower case model names to model classes. Initially set to
                                                    # None to prevent accidental access before import_models() runs.
                                                    self.models = None
                                            }
                                        }

                                    # 如:app_config === django.contrib.sessions.apps.SessionsConfig
                                    # 获取 app_config 对象的属性
                                    if app_config.label in self.app_configs:
                                        raise ImproperlyConfigured(
                                            "Application labels aren't unique, "
                                            "duplicates: %s" % app_config.label)

                                    # 保存 app_config 对象到 map 结构 
                                    self.app_configs[app_config.label] = app_config
                                    # !!! 设置 app_config 对 django.apps.registry.Apps 的依赖 !!!
                                    app_config.apps = self

                                # !!!!!!!!!!!! 至此,迭代完所有的 settings.INSTALLED_APPS !!!!!!!!!!!!

                                # 所有应用的配置
                                # Check for duplicate app names.
                                counts = Counter(
                                    app_config.name for app_config in self.app_configs.values())
                                duplicates = [
                                    name for name, count in counts.most_common() if count > 1]
                                if duplicates: # 重复
                                    raise ImproperlyConfigured(
                                        "Application names aren't unique, "
                                        "duplicates: %s" % ", ".join(duplicates))

                                self.apps_ready = True

                                # 阶段2:迭代 app_config,导入 models 模块  ------------------ app_configs ------------------- 1.15
                                # Phase 2: import models modules.
                                for app_config in self.app_configs.values():
                                    # 如:app_config === django.contrib.sessions.apps.SessionsConfig
                                    app_config.import_models()
                                    {
                                        # 如:self.apps === django.apps.registry.Apps
                                        self.models = self.apps.all_models[self.label]

                                        # !!! 导入子模块
                                        # 如:self.module === django.contrib.sessions
                                        if module_has_submodule(self.module, MODELS_MODULE_NAME):
                                            # MODELS_MODULE_NAME === models
                                            # 如:django.contrib.sessions.models
                                            models_module_name = '%s.%s' % (self.name, MODELS_MODULE_NAME)
                                            # 导入 django.contrib.sessions.models 模块
                                            self.models_module = import_module(models_module_name)
                                    }

                                self.clear_cache()

                                self.models_ready = True

                                # 阶段 3: 迭代 app_config,调用 app_config 的 ready() 方法
                                # Phase 3: run ready() methods of app configs.
                                for app_config in self.get_app_configs():
                                    app_config.ready()

                                self.ready = True
                        }

                    }

            self.autocomplete()
            {
                # Don't complete if user hasn't sourced bash_completion file.
                if 'DJANGO_AUTO_COMPLETE' not in os.environ:
                    return

                ......
            }

            if subcommand == 'help':
                if '--commands' in args:
                    sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
                elif len(options.args) < 1:
                    sys.stdout.write(self.main_help_text() + '\n')
                else:
                    self.fetch_command(options.args[0]).print_help(self.prog_name, options.args[0])
            # Special-cases: We want 'django-admin --version' and
            # 'django-admin --help' to work, for backwards compatibility.
            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){
                    # 获取 commands 列表
                    # Get commands outside of try block to prevent swallowing exceptions
                    commands = get_commands()
                    {
                        commands = {name: 'django.core' for name in find_commands(upath(__path__[0])){
                            # 如:management_dir === upath(__path__[0])
                            # 如:management_dir === /Library/Python/2.7/site-packages/django/core/management
                            # 如:command_dir === /Library/Python/2.7/site-packages/django/core/management/commands
                            command_dir = os.path.join(management_dir, 'commands')
                            return [name for _, name, is_pkg in pkgutil.iter_modules([npath(command_dir)])
                                    if not is_pkg and not name.startswith('_')]
                        }}

                        if not settings.configured:
                            return commands

                        # 迭代 app_config 列表中的 commands
                        for app_config in reversed(list(apps.get_app_configs())):
                            path = os.path.join(app_config.path, 'management')
                            # 查找 app_config 中的 Command 对象
                            commands.update({name: app_config.name for name in find_commands(path)})

                        return commands
                    }

                    try:
                        # 命中 Command 对象
                        # commands === {
                        #    'check': 'django.core',
                        #    'compilemessages': 'django.core',
                        #    'runserver': 'django.core'
                        #    ...
                        # }
                        app_name = commands[subcommand]
                    except KeyError:
                        if os.environ.get('DJANGO_SETTINGS_MODULE'):
                            # If `subcommand` is missing due to misconfigured settings, the
                            # following line will retrigger an ImproperlyConfigured exception
                            # (get_commands() swallows the original one) so the user is
                            # informed about it.
                            settings.INSTALLED_APPS
                        else:
                            sys.stderr.write("No Django settings specified.\n")
                        sys.stderr.write(
                            "Unknown command: %r\nType '%s help' for usage.\n"
                            % (subcommand, self.prog_name)
                        )
                        sys.exit(1)

                    if isinstance(app_name, BaseCommand):
                        # If the command is already loaded, use it directly.
                        klass = app_name
                    else:
                        # 实例化 Command 对象
                        # 如: app_name === 'django.core',subcommand === 'runserver'
                        klass = load_command_class(app_name, subcommand)
                        {
                            # 如: module === django.core.management.commands.runserver
                            # 导入模块 /Library/Python/2.7/site-packages/django/core/management/commands/runserver.py
                            module = import_module('%s.management.commands.%s' % (app_name, name))

                            # 实例化 Command 对象
                            # 如:module.Command() === django.core.management.commands.runserver.Command()
                            return module.Command()
                        }
                        
                    # 如: klass === django.core.management.commands.runserver.Command()
                    return klass
                }
                .run_from_argv(self.argv) # 根据参数运行
                {
                    # !!!! 执行 django.core.management.commands.runserver.Command().run_from_argv(self.argv)
                     
                    self._called_from_command_line = True

                    # 创建参数解析器
                    parser = self.create_parser(argv[0], argv[1])
                    {
                        parser = CommandParser(
                            self, prog="%s %s" % (os.path.basename(prog_name), subcommand),
                            description=self.help or None,
                        )
                        parser.add_argument('--version', action='version', version=self.get_version())
                        parser.add_argument(
                            '-v', '--verbosity', action='store', dest='verbosity', default=1,
                            type=int, choices=[0, 1, 2, 3],
                            help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output',
                        )
                        parser.add_argument(
                            '--settings',
                            help=(
                                'The Python path to a settings module, e.g. '
                                '"myproject.settings.main". If this isn\'t provided, the '
                                'DJANGO_SETTINGS_MODULE environment variable will be used.'
                            ),
                        )
                        parser.add_argument(
                            '--pythonpath',
                            help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".',
                        )
                        parser.add_argument('--traceback', action='store_true', help='Raise on CommandError exceptions')
                        parser.add_argument(
                            '--no-color', action='store_true', dest='no_color', default=False,
                            help="Don't colorize the command output.",
                        )
                        self.add_arguments(parser)
                        return parser
                    }

                    # 解析参数
                    options = parser.parse_args(argv[2:])
                    cmd_options = vars(options)
                    # Move positional args out of options to mimic legacy optparse
                    args = cmd_options.pop('args', ())

                    # 处理默认选项
                    handle_default_options(options)
                    {
                        if options.settings:
                            os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
                        if options.pythonpath:
                            sys.path.insert(0, options.pythonpath)
                    }

                    # !!!执行 !!!
                    try:
                        self.execute(*args, **cmd_options)
                        {
                            # 调用子类
                            if options['no_color']:
                                # We rely on the environment because it's currently the only
                                # way to reach WSGIRequestHandler. This seems an acceptable
                                # compromise considering `runserver` runs indefinitely.
                                os.environ[str("DJANGO_COLORS")] = str("nocolor")
                            
                            # 调用父类 execute - begain
                            super(Command, self).execute(*args, **options)
                            {
                                if options['no_color']:
                                    self.style = no_style()
                                    self.stderr.style_func = None
                                if options.get('stdout'):
                                    self.stdout = OutputWrapper(options['stdout'])
                                if options.get('stderr'):
                                    self.stderr = OutputWrapper(options['stderr'], self.stderr.style_func)
                        
                                saved_locale = None
                                if not self.leave_locale_alone:
                                    # Deactivate translations, because django-admin creates database
                                    # content like permissions, and those shouldn't contain any
                                    # translations.
                                    from django.utils import translation
                                    saved_locale = translation.get_language()
                                    translation.deactivate_all()
                        
                                try:
                                    if self.requires_system_checks and not options.get('skip_checks'):
                                        self.check()
                                    if self.requires_migrations_checks:
                                        self.check_migrations()
                                        
                                    # !!! ------ 调用子类的 handle 方法 -------
                                    output = self.handle(*args, **options)
                                    {
                                        from django.conf import settings

                                        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']:
                                            self.addr = ''
                                            self.port = self.default_port
                                        else:
                                            m = re.match(naiveip_re, options['addrport'])
                                            if m is None:
                                                raise CommandError('"%s" is not a valid port number '
                                                                   'or address:port pair.' % options['addrport'])
                                            self.addr, _ipv4, _ipv6, _fqdn, self.port = m.groups()
                                            if not self.port.isdigit():
                                                raise CommandError("%r is not a valid port number." % self.port)
                                            if self.addr:
                                                if _ipv6:
                                                    self.addr = self.addr[1:-1]
                                                    self.use_ipv6 = True
                                                    self._raw_ipv6 = True
                                                elif self.use_ipv6 and not _fqdn:
                                                    raise CommandError('"%s" is not a valid IPv6 address.' % self.addr)
                                        if not self.addr:
                                            self.addr = '::1' if self.use_ipv6 else '127.0.0.1'
                                            self._raw_ipv6 = self.use_ipv6
                                            
                                        # !!! ------ 调用 run() 方法 ------------
                                        self.run(**options)
                                        {
                                            # 是否使用自动加载器
                                            use_reloader = options['use_reloader']
                                    
                                            if use_reloader:
                                                # 包装 self.inner_run 函数
                                                autoreload.main(self.inner_run, None, options)
                                                {
                                                    if args is None:
                                                        args = ()
                                                    if kwargs is None:
                                                        kwargs = {}
                                                    if sys.platform.startswith('java'):
                                                        reloader = jython_reloader
                                                    else:
                                                        reloader = python_reloader
                                                
                                                    wrapped_main_func = check_errors(main_func)
                                                    {
                                                        def wrapper(*args, **kwargs):
                                                            global _exception
                                                            try:
                                                                # 执行 inner_run 函数
                                                                fn(*args, **kwargs)
                                                            except Exception:
                                                                _exception = sys.exc_info()
                                                    
                                                                et, ev, tb = _exception
                                                    
                                                                if getattr(ev, 'filename', None) is None:
                                                                    # get the filename from the last item in the stack
                                                                    filename = traceback.extract_tb(tb)[-1][0]
                                                                else:
                                                                    filename = ev.filename
                                                    
                                                                if filename not in _error_files:
                                                                    _error_files.append(filename)
                                                    
                                                                raise
                                                    
                                                        return wrapper
                                                    }
                                                    
                                                    # 当  reloader = python_reloader
                                                    reloader(wrapped_main_func, args, kwargs)
                                                    {
                                                        # main_func === wrapped_main_func
                                                        if os.environ.get("RUN_MAIN") == "true":
                                                            # !!!执行 wrapped_main_func 函数
                                                            thread.start_new_thread(main_func, args, kwargs)
                                                            # !!!启动监控,监控代码是否改变
                                                            try:
                                                                reloader_thread()
                                                                {
                                                                    ensure_echo_on()
                                                                    if USE_INOTIFY:
                                                                        fn = inotify_code_changed
                                                                    else:
                                                                        fn = code_changed
                                                                    while RUN_RELOADER:
                                                                        # 文件改变
                                                                        change = fn()
                                                                        if change == FILE_MODIFIED: 
                                                                            sys.exit(3)  # force reload 强制重新启动,退出码=3
                                                                        elif change == I18N_MODIFIED:
                                                                            reset_translations()
                                                                        time.sleep(1)
                                                                }
                                                            except KeyboardInterrupt:
                                                                pass
                                                        else:
                                                            try:
                                                                exit_code = restart_with_reloader()
                                                                {
                                                                    while True: # 无限循环
                                                                        args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions] + sys.argv
                                                                        new_environ = os.environ.copy()
                                                                        if _win and six.PY2:
                                                                            # Environment variables on Python 2 + Windows must be str.
                                                                            encoding = get_system_encoding()
                                                                            for key in new_environ.keys():
                                                                                str_key = key.decode(encoding).encode('utf-8')
                                                                                str_value = new_environ[key].decode(encoding).encode('utf-8')
                                                                                del new_environ[key]
                                                                                new_environ[str_key] = str_value
                                                                        # 设置环境
                                                                        new_environ["RUN_MAIN"] = 'true'
                                                                        # 启动子进程,并等待 exit_code
                                                                        exit_code = subprocess.call(args, env=new_environ)
                                                                        if exit_code != 3: # 退出码!=3
                                                                            return exit_code
                                                                }
                                                                if exit_code < 0:
                                                                    os.kill(os.getpid(), -exit_code)
                                                                else:
                                                                    sys.exit(exit_code)
                                                            except KeyboardInterrupt:
                                                                pass
                                                    }
                                                }
                                            else:
                                                # ------------ !!! 运行 !!! ------------
                                                self.inner_run(None, **options)
                                                {
                                                    # If an exception was silenced in ManagementUtility.execute in order
                                                    # to be raised in the child process, raise it now.
                                                    autoreload.raise_last_exception()
                                            
                                                    # 使用线程
                                                    threading = options['use_threading']
                                                    # 'shutdown_message' is a stealth option.
                                                    shutdown_message = options.get('shutdown_message', '')
                                                    quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
                                            
                                                    self.stdout.write("Performing system checks...\n\n")
                                                    self.check(display_num_errors=True)
                                                    # Need to check migrations here, so can't use the
                                                    # requires_migrations_check attribute.
                                                    self.check_migrations()
                                                    now = datetime.now().strftime('%B %d, %Y - %X')
                                                    if six.PY2:
                                                        now = now.decode(get_system_encoding())
                                                    self.stdout.write(now)
                                                    self.stdout.write((
                                                        "Django version %(version)s, using settings %(settings)r\n"
                                                        "Starting development server at %(protocol)s://%(addr)s:%(port)s/\n"
                                                        "Quit the server with %(quit_command)s.\n"
                                                    ) % {
                                                        "version": self.get_version(),
                                                        "settings": settings.SETTINGS_MODULE,
                                                        "protocol": self.protocol,
                                                        "addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
                                                        "port": self.port,
                                                        "quit_command": quit_command,
                                                    })
                                            
                                                    try:
                                                        # handler === django.core.handlers.wsgi.WSGIHandler
                                                        handler = self.get_handler(*args, **options)
                                                        {
                                                            return get_internal_wsgi_application()
                                                            {
                                                                from django.conf import settings
                                                                app_path = getattr(settings, 'WSGI_APPLICATION')
                                                                if app_path is None:
                                                                    return get_wsgi_application()
                                                                    {
                                                                        # 安装
                                                                        django.setup(set_prefix=False)
                                                                        {
                                                                            from django.apps import apps
                                                                            from django.conf import settings
                                                                            from django.urls import set_script_prefix
                                                                            from django.utils.encoding import force_text
                                                                            from django.utils.log import configure_logging
                                                                            # 日志
                                                                            configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
                                                                            if set_prefix:
                                                                                set_script_prefix(
                                                                                    '/' if settings.FORCE_SCRIPT_NAME is None else force_text(settings.FORCE_SCRIPT_NAME)
                                                                                )
                                                                            # 填充 settings.INSTALLED_APPS
                                                                            apps.populate(settings.INSTALLED_APPS)
                                                                        }
                                                                        
                                                                        # 创建 django.core.handlers.wsgi.WSGIHandler 对象
                                                                        return WSGIHandler(){
                                                                            def __init__(self, *args, **kwargs):
                                                                                super(WSGIHandler, self).__init__(*args, **kwargs)
                                                                                {
                                                                                    self._request_middleware = None
                                                                                    self._view_middleware = None
                                                                                    self._template_response_middleware = None
                                                                                    self._response_middleware = None
                                                                                    self._exception_middleware = None
                                                                                    self._middleware_chain = None
                                                                                }
                                                                                
                                                                                # ------ 加载 中间件
                                                                                self.load_middleware()
                                                                                {
                                                                                    self._request_middleware = []
                                                                                    self._view_middleware = []
                                                                                    self._template_response_middleware = []
                                                                                    self._response_middleware = []
                                                                                    self._exception_middleware = []
                                                                                    
                                                                                    # -------------------- 中间件 settings.MIDDLEWARE ------------- 1 !!!
                                                                                    if settings.MIDDLEWARE is None:
                                                                                        warnings.warn(
                                                                                            "Old-style middleware using settings.MIDDLEWARE_CLASSES is "
                                                                                            "deprecated. Update your middleware and use settings.MIDDLEWARE "
                                                                                            "instead.", RemovedInDjango20Warning
                                                                                        )
                                                                                        handler = convert_exception_to_response(self._legacy_get_response)
                                                                                        
                                                                                        for middleware_path in settings.MIDDLEWARE_CLASSES:
                                                                                            mw_class = import_string(middleware_path)
                                                                                            try:
                                                                                                mw_instance = mw_class()
                                                                                            except MiddlewareNotUsed as exc:
                                                                                                if settings.DEBUG:
                                                                                                    if six.text_type(exc):
                                                                                                        logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
                                                                                                    else:
                                                                                                        logger.debug('MiddlewareNotUsed: %r', middleware_path)
                                                                                                continue
                                                                            
                                                                                            if hasattr(mw_instance, 'process_request'):
                                                                                                self._request_middleware.append(mw_instance.process_request)
                                                                                            if hasattr(mw_instance, 'process_view'):
                                                                                                self._view_middleware.append(mw_instance.process_view)
                                                                                            if hasattr(mw_instance, 'process_template_response'):
                                                                                                self._template_response_middleware.insert(0, mw_instance.process_template_response)
                                                                                            if hasattr(mw_instance, 'process_response'):
                                                                                                self._response_middleware.insert(0, mw_instance.process_response)
                                                                                            if hasattr(mw_instance, 'process_exception'):
                                                                                                self._exception_middleware.insert(0, mw_instance.process_exception)
                                                                                    else:
                                                                                        # !!! convert_exception_to_response 的用途是:包装一层 _get_response 函数,并添加捕获 _get_response 异常的代码
                                                                                        handler = convert_exception_to_response(self._get_response)
                                                                                        {
                                                                                            # def convert_exception_to_response(get_response):
                                                                                                @wraps(get_response, assigned=available_attrs(get_response))
                                                                                                def inner(request):
                                                                                                    try:
                                                                                                        # get_response === self._get_response
                                                                                                        response = get_response(request)
                                                                                                        {
                                                                                                            # def _get_response(self, request):
                                                                                                                response = None

                                                                                                                # !!! 路由解析器
                                                                                                                if hasattr(request, 'urlconf'):
                                                                                                                    urlconf = request.urlconf
                                                                                                                    set_urlconf(urlconf)
                                                                                                                    resolver = get_resolver(urlconf)
                                                                                                                else:
                                                                                                                    resolver = get_resolver()
                                                                                                                    {
                                                                                                                        @lru_cache.lru_cache(maxsize=None)
                                                                                                                        def get_resolver(urlconf=None):
                                                                                                                            if urlconf is None:
                                                                                                                                from django.conf import settings
                                                                                                                                # ------------------------------------------------------------------- !!!获取 settings.ROOT_URLCONF 信息
                                                                                                                                urlconf = settings.ROOT_URLCONF
                                                                                                                            # urlconf === 'DebugApp.urls'
                                                                                                                            return RegexURLResolver(r'^/', urlconf)
                                                                                                                            {
                                                                                                                                # RegexURLResolver 构造函数
                                                                                                                                def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
                                                                                                                                    LocaleRegexProvider.__init__(self, regex)
                                                                                                                                    {
                                                                                                                                        # LocaleRegexProvider 构造函数
                                                                                                                                        def __init__(self, regex):
                                                                                                                                            # regex is either a string representing a regular expression, or a
                                                                                                                                            # translatable string (using ugettext_lazy) representing a regular
                                                                                                                                            # expression.
                                                                                                                                            self._regex = regex
                                                                                                                                            self._regex_dict = {}
                                                                                                                                        regex = LocaleRegexDescriptor()
                                                                                                                                    }
                                                                                                                                    # urlconf_name is the dotted Python path to the module defining
                                                                                                                                    # urlpatterns. It may also be an object with an urlpatterns attribute
                                                                                                                                    # or urlpatterns itself.
                                                                                                                                    self.urlconf_name = urlconf_name
                                                                                                                                    self.callback = None
                                                                                                                                    self.default_kwargs = default_kwargs or {}
                                                                                                                                    self.namespace = namespace
                                                                                                                                    self.app_name = app_name
                                                                                                                                    self._reverse_dict = {}
                                                                                                                                    self._namespace_dict = {}
                                                                                                                                    self._app_dict = {}
                                                                                                                                    # set of dotted paths to all functions and classes that are used in
                                                                                                                                    # urlpatterns
                                                                                                                                    self._callback_strs = set()
                                                                                                                                    self._populated = False
                                                                                                                                    self._local = threading.local()
                                                                                                                            }
                                                                                                                    }
                                                                                                                
                                                                                                                # !!! ------------------------ 匹配出路由 ------------------------ !!!
                                                                                                                resolver_match = resolver.resolve(request.path_info)
                                                                                                                {
                                                                                                                    path = force_text(path)  # path may be a reverse_lazy object
                                                                                                                    tried = []
                                                                                                                    # 匹配 '/'
                                                                                                                    match = self.regex.search(path)
                                                                                                                    if match:
                                                                                                                        new_path = path[match.end():]
                                                                                                                        # self.url_patterns = {
                                                                                                                        #    @cached_property
                                                                                                                        #    def url_patterns(self):
                                                                                                                        #        # urlconf_module might be a valid set of patterns, so we default to it
                                                                                                                        #        # 导入模块
                                                                                                                        #        # self.urlconf_module = {
                                                                                                                        #        #    @cached_property
                                                                                                                        #        #    def urlconf_module(self):
                                                                                                                        #        #        if isinstance(self.urlconf_name, six.string_types):
                                                                                                                        #        #            return import_module(self.urlconf_name)
                                                                                                                        #        #        else:
                                                                                                                        #        #            return self.urlconf_name
                                                                                                                        #        # }
                                                                                                                        #        patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
                                                                                                                        #        try:
                                                                                                                        #            iter(patterns)
                                                                                                                        #        except TypeError:
                                                                                                                        #            msg = (
                                                                                                                        #                "The included URLconf '{name}' does not appear to have any "
                                                                                                                        #                "patterns in it. If you see valid patterns in the file then "
                                                                                                                        #                "the issue is probably caused by a circular import."
                                                                                                                        #            )
                                                                                                                        #            raise ImproperlyConfigured(msg.format(name=self.urlconf_name))
                                                                                                                        #        return patterns
                                                                                                                        # }
                                                                                                                        # 迭代所以配置的路由,进行匹配
                                                                                                                        for pattern in self.url_patterns:
                                                                                                                            try:
                                                                                                                                # 匹配到路由
                                                                                                                                sub_match = pattern.resolve(new_path)
                                                                                                                            except Resolver404 as e:
                                                                                                                                sub_tried = e.args[0].get('tried')
                                                                                                                                if sub_tried is not None:
                                                                                                                                    tried.extend([pattern] + t for t in sub_tried)
                                                                                                                                else:
                                                                                                                                    tried.append([pattern])
                                                                                                                            else:
                                                                                                                                if sub_match:
                                                                                                                                    # Merge captured arguments in match with submatch
                                                                                                                                    sub_match_dict = dict(match.groupdict(), **self.default_kwargs)
                                                                                                                                    sub_match_dict.update(sub_match.kwargs)
                                                                                                            
                                                                                                                                    # If there are *any* named groups, ignore all non-named groups.
                                                                                                                                    # Otherwise, pass all non-named arguments as positional arguments.
                                                                                                                                    sub_match_args = sub_match.args
                                                                                                                                    if not sub_match_dict:
                                                                                                                                        sub_match_args = match.groups() + sub_match.args
                                                                                                            
                                                                                                                                    return ResolverMatch(
                                                                                                                                        sub_match.func, # 回调函数
                                                                                                                                        sub_match_args, # 参数
                                                                                                                                        sub_match_dict,
                                                                                                                                        sub_match.url_name,
                                                                                                                                        [self.app_name] + sub_match.app_names,
                                                                                                                                        [self.namespace] + sub_match.namespaces,
                                                                                                                                    )
                                                                                                                                tried.append([pattern])
                                                                                                                        raise Resolver404({'tried': tried, 'path': new_path})
                                                                                                                    raise Resolver404({'path': path})
                                                                                                                }
                                                                                                                # callback = 要调用的函数
                                                                                                                # callback_args = 函数参数
                                                                                                                # callback_kwargs = 函数的动态参数
                                                                                                                callback, callback_args, callback_kwargs = resolver_match
                                                                                                                request.resolver_match = resolver_match
                                                                                                        
                                                                                                                # Apply view middleware 
                                                                                                                # !!! 应用 _view_middleware 类型的中间件
                                                                                                                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 ===  用户定义的 action
                                                                                                                    wrapped_callback = self.make_view_atomic(callback)
                                                                                                                    try:
                                                                                                                        # ------------------------------ 执行用户定义的 action
                                                                                                                        response = wrapped_callback(request, *callback_args, **callback_kwargs)
                                                                                                                    except Exception as e:
                                                                                                                        response = self.process_exception_by_middleware(e, request)
                                                                                                        
                                                                                                                # Complain if the view returned None (a common error).
                                                                                                                if response is None:
                                                                                                                    if isinstance(callback, types.FunctionType):    # FBV
                                                                                                                        view_name = callback.__name__
                                                                                                                    else:                                           # CBV
                                                                                                                        view_name = callback.__class__.__name__ + '.__call__'
                                                                                                        
                                                                                                                    raise ValueError(
                                                                                                                        "The view %s.%s didn't return an HttpResponse object. It "
                                                                                                                        "returned None instead." % (callback.__module__, view_name)
                                                                                                                    )
                                                                                                        
                                                                                                                # 对象 response 有 render 方法,那么进行调用 render
                                                                                                                # If the response supports deferred rendering, apply template
                                                                                                                # response middleware and then render the response
                                                                                                                elif hasattr(response, 'render') and callable(response.render):
                                                                                                                    # 应用 _template_response_middleware 类型的中间件
                                                                                                                    for middleware_method in self._template_response_middleware:
                                                                                                                        response = middleware_method(request, response)
                                                                                                                        # Complain if the template response middleware returned None (a common error).
                                                                                                                        if response is None:
                                                                                                                            raise ValueError(
                                                                                                                                "%s.process_template_response didn't return an "
                                                                                                                                "HttpResponse object. It returned None instead."
                                                                                                                                % (middleware_method.__self__.__class__.__name__)
                                                                                                                            )
                                                                                                        
                                                                                                                    try:
                                                                                                                        # 调用 render 方法
                                                                                                                        response = response.render()
                                                                                                                    except Exception as e:
                                                                                                                        response = self.process_exception_by_middleware(e, request)
                                                                                                        
                                                                                                                return response
                                                                                                        }
                                                                                                    except Exception as exc:
                                                                                                        response = response_for_exception(request, exc)
                                                                                                    return response
                                                                                                return inner # ------------
                                                                                        }
                                                                                        # handler = inner(request){ ... }
                                                                                        
                                                                                        # -------------------- 中间件列表 settings.MIDDLEWARE ------------- 1 !!!
                                                                                        # 反转 中间件列表,并包装 handler
                                                                                        for middleware_path in reversed(settings.MIDDLEWARE):
                                                                                            middleware = import_string(middleware_path)
                                                                                            try:
                                                                                                # 用 middleware 包裹 handler
                                                                                                mw_instance = middleware(handler)
                                                                                            except MiddlewareNotUsed as exc:
                                                                                                if settings.DEBUG:
                                                                                                    if six.text_type(exc):
                                                                                                        logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
                                                                                                    else:
                                                                                                        logger.debug('MiddlewareNotUsed: %r', middleware_path)
                                                                                                continue
                                                                            
                                                                                            if mw_instance is None:
                                                                                                raise ImproperlyConfigured(
                                                                                                    'Middleware factory %s returned None.' % middleware_path
                                                                                                )
                                                                            
                                                                                            if hasattr(mw_instance, 'process_view'):
                                                                                                # process_view 中间件
                                                                                                self._view_middleware.insert(0, mw_instance.process_view)
                                                                                            if hasattr(mw_instance, 'process_template_response'):
                                                                                                # process_template_response 中间件
                                                                                                self._template_response_middleware.append(mw_instance.process_template_response)
                                                                                            if hasattr(mw_instance, 'process_exception'):
                                                                                                # process_exception 中间件
                                                                                                self._exception_middleware.append(mw_instance.process_exception)
                                                                                            # !!! convert_exception_to_response 的用途是:包装一层 mw_instance 函数,并添加捕获 mw_instance 异常的代码
                                                                                            handler = convert_exception_to_response(mw_instance)
                                                                            
                                                                                    # -------------------- middleware 链条
                                                                                    # We only assign to this when initialization is complete as it is used
                                                                                    # as a flag for initialization being complete.
                                                                                    self._middleware_chain = handler
                                                                                }
                                                                        }
                                                                    }
                                                            
                                                                try:
                                                                    return import_string(app_path)
                                                                except ImportError as e:
                                                                    msg = (
                                                                        "WSGI application '%(app_path)s' could not be loaded; "
                                                                        "Error importing module: '%(exception)s'" % ({
                                                                            'app_path': app_path,
                                                                            'exception': e,
                                                                        })
                                                                    )
                                                                    six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg),
                                                                                sys.exc_info()[2])
                                                            
                                                            }
                                                        }
                                                        
                                                        # handler === django.core.handlers.wsgi.WSGIHandler
                                                        # 执行
                                                        # default_port = '8000'
                                                        # protocol = 'http'
                                                        # server_cls = django.core.servers.basehttp.WSGIServer
                                                        run(self.addr, int(self.port), handler,ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
                                                        {
                                                            server_address = (addr, port)
                                                            if threading:
                                                                # 多线程的支持
                                                                # 让 socketserver.ThreadingMixIn 继承,并重新 server_cls 内的方法
                                                                httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, server_cls), {})
                                                            else:
                                                                # 单线程
                                                                # httpd_cls = django.core.servers.basehttp.WSGIServer
                                                                httpd_cls = server_cls
                                                                
                                                            httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
                                                            {
                                                                def __init__(self, *args, **kwargs):
                                                                    if kwargs.pop('ipv6', False):
                                                                        self.address_family = socket.AF_INET6
                                                                    self.allow_reuse_address = kwargs.pop('allow_reuse_address', True)
                                                                    super(WSGIServer, self).__init__(*args, **kwargs)
                                                                    {
                                                                        # TCPServer
                                                                        def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
                                                                            BaseServer.__init__(self, server_address, RequestHandlerClass)
                                                                            {
                                                                                def __init__(self, server_address, RequestHandlerClass):
                                                                                    self.server_address = server_address
                                                                                    # ------- RequestHandlerClass ------- 处理类 
                                                                                    self.RequestHandlerClass = RequestHandlerClass
                                                                                    self.__is_shut_down = threading.Event()
                                                                                    self.__shutdown_request = False
                                                                            }
                                                                            # 创建 socket
                                                                            self.socket = socket.socket(self.address_family, self.socket_type)
                                                                            if bind_and_activate:
                                                                                try:
                                                                                    self.server_bind()
                                                                                    {
                                                                                        # WSGIServer
                                                                                        def server_bind(self):
                                                                                            HTTPServer.server_bind(self)
                                                                                            {
                                                                                                # HTTPServer
                                                                                                def server_bind(self):
                                                                                                    # TCPServer
                                                                                                    SocketServer.TCPServer.server_bind(self)
                                                                                                    {
                                                                                                        def server_bind(self):
                                                                                                            if self.allow_reuse_address:
                                                                                                                self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                                                                                                            # 设置监听地址
                                                                                                            self.socket.bind(self.server_address)
                                                                                                            self.server_address = self.socket.getsockname()
                                                                                                    }
                                                                                                    host, port = self.socket.getsockname()[:2]
                                                                                                    self.server_name = socket.getfqdn(host)
                                                                                                    self.server_port = port
                                                                                            }
                                                                                            # WSGIServer
                                                                                            self.setup_environ()
                                                                                            {
                                                                                                def setup_environ(self):
                                                                                                    # Set up base environment
                                                                                                    env = self.base_environ = {}
                                                                                                    env['SERVER_NAME'] = self.server_name
                                                                                                    env['GATEWAY_INTERFACE'] = 'CGI/1.1'
                                                                                                    env['SERVER_PORT'] = str(self.server_port)
                                                                                                    env['REMOTE_HOST']=''
                                                                                                    env['CONTENT_LENGTH']=''
                                                                                                    env['SCRIPT_NAME'] = ''
                                                                                            }
                                                                                    }
                                                                                    self.server_activate()
                                                                                    {
                                                                                        def server_activate(self):
                                                                                            # 设置监听队列
                                                                                            self.socket.listen(self.request_queue_size)
                                                                                    }
                                                                                except:
                                                                                    self.server_close()
                                                                                    raise
                                                                    
                                                                    }
                                                            }
                                                            if threading:
                                                                # ThreadingMixIn.daemon_threads indicates how threads will behave on an
                                                                # abrupt shutdown; like quitting the server by the user or restarting
                                                                # by the auto-reloader. True means the server will not wait for thread
                                                                # termination before it quits. This will make auto-reloader faster
                                                                # and will prevent the need to kill the server manually if a thread
                                                                # isn't terminating correctly.
                                                                httpd.daemon_threads = True
                                                                
                                                            # 设置 wsgi_handler 处理器 
                                                            # 如:httpd = django.core.servers.basehttp.WSGIServer
                                                            # 如:wsgi_handler == django.core.handlers.wsgi.WSGIHandler
                                                            httpd.set_app(wsgi_handler)
                                                            {
                                                                def set_app(self,application):
                                                                    # 如:application == django.core.handlers.wsgi.WSGIHandler
                                                                    self.application = application
                                                            }
                                                            
                                                            # 执行监听
                                                            # 如:httpd = django.core.servers.basehttp.WSGIServer
                                                            httpd.serve_forever()
                                                            {
                                                                def serve_forever(self, poll_interval=0.5):
                                                                    self.__is_shut_down.clear()
                                                                    try:
                                                                        # 死循环
                                                                        while not self.__shutdown_request:
                                                                            # 通过 select.select 获取连接句柄
                                                                            # XXX: Consider using another file descriptor or
                                                                            # connecting to the socket to wake this up instead of
                                                                            # polling. Polling reduces our responsiveness to a
                                                                            # shutdown request and wastes cpu at all other times.
                                                                            r, w, e = _eintr_retry(select.select, [self], [], [],poll_interval)
                                                                            {
                                                                                 def _eintr_retry(func, *args):
                                                                                    # restart a system call interrupted by EINTR
                                                                                    while True:
                                                                                        try:
                                                                                            return func(*args)
                                                                                        except (OSError, select.error) as e:
                                                                                            if e.args[0] != errno.EINTR:
                                                                                                raise
                                                                            }   
                                                                            # 读句柄
                                                                            if self in r:
                                                                                self._handle_request_noblock()
                                                                                {
                                                                                    def _handle_request_noblock(self):
                                                                                        # Handle one request, without blocking.
                                                                                        # I assume that select.select has returned that the socket is
                                                                                        # readable before this function was called, so there should be
                                                                                        # no risk of blocking in get_request().
                                                                                        try:
                                                                                            # 获取连接 request === connection 
                                                                                            request, client_address = self.get_request()
                                                                                            {
                                                                                                def get_request(self):
                                                                                                    # Get the request and client address from the socket.
                                                                                                    # May be overridden.
                                                                                                    return self.socket.accept()
                                                                                            }
                                                                                        except socket.error:
                                                                                            return
                                                                                        # 连接 request === connection 
                                                                                        if self.verify_request(request, client_address):
                                                                                            try:
                                                                                                # 单进程/单线程方案,不会被重写
                                                                                                # 多线程方案,socketserver.ThreadingMixIn 会重写 process_request(...) 方法
                                                                                                # 多进程方案,socketserver.ForkingMixIn 会重写 process_request(...) 方法
                                                                                                # 获取连接 request === connection 
                                                                                                self.process_request(request, client_address)
                                                                                                {
                                                                                                    # 连接 request === connection 
                                                                                                    def process_request(self, request, client_address):
                                                                                                        # Call finish_request.
                                                                                                        # Overridden by ForkingMixIn and ThreadingMixIn.
                                                                                                        self.finish_request(request, client_address)
                                                                                                        {
                                                                                                            def finish_request(self, request, client_address):
                                                                                                                # 执行请求 request === connection 
                                                                                                                # RequestHandlerClass === django.core.servers.basehttp.WSGIRequestHandler
                                                                                                                # Finish one request by instantiating RequestHandlerClass.
                                                                                                                self.RequestHandlerClass(request, client_address, self)
                                                                                                                {
                                                                                                                    # BaseRequestHandler
                                                                                                                    def __init__(self, request, client_address, server):
                                                                                                                        # request 对象 request == connection
                                                                                                                        self.request = request
                                                                                                                        self.client_address = client_address
                                                                                                                        # 如: server == django.core.servers.basehttp.WSGIServer
                                                                                                                        self.server = server
                                                                                                                        # 安装请求 === django.core.servers.basehttp.WSGIRequestHandler.setup()
                                                                                                                        self.setup()
                                                                                                                        {
                                                                                                                            # SocketServer.StreamRequestHandler
                                                                                                                            def setup(self):
                                                                                                                                # 连接 connection == request
                                                                                                                                self.connection = self.request
                                                                                                                                if self.timeout is not None:
                                                                                                                                    self.connection.settimeout(self.timeout)
                                                                                                                                if self.disable_nagle_algorithm:
                                                                                                                                    self.connection.setsockopt(socket.IPPROTO_TCP,
                                                                                                                                                               socket.TCP_NODELAY, True)
                                                                                                                                # 读句柄
                                                                                                                                self.rfile = self.connection.makefile('rb', self.rbufsize)
                                                                                                                                # 写句柄
                                                                                                                                self.wfile = self.connection.makefile('wb', self.wbufsize)
                                                                                                                        }
                                                                                                                        try:
                                                                                                                            # 处理请求 === django.core.servers.basehttp.WSGIRequestHandler.handle()
                                                                                                                            self.handle()
                                                                                                                            {
                                                                                                                                # django.core.servers.basehttp.WSGIRequestHandler.handle()
                                                                                                                                def handle(self):
                                                                                                                                    # 获取 65537 行数据
                                                                                                                                    # Copy of WSGIRequestHandler, 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(){
                                                                                                                                        self.command = None  # set in case of error on the first line
                                                                                                                                        self.request_version = version = self.default_request_version
                                                                                                                                        self.close_connection = 1
                                                                                                                                        requestline = self.raw_requestline
                                                                                                                                        requestline = requestline.rstrip('\r\n')
                                                                                                                                        self.requestline = requestline
                                                                                                                                        words = requestline.split()
                                                                                                                                        if len(words) == 3:
                                                                                                                                            command, path, version = words
                                                                                                                                            if version[:5] != 'HTTP/':
                                                                                                                                                self.send_error(400, "Bad request version (%r)" % version)
                                                                                                                                                return False
                                                                                                                                            try:
                                                                                                                                                # http 版本信息
                                                                                                                                                base_version_number = version.split('/', 1)[1]
                                                                                                                                                version_number = base_version_number.split(".")
                                                                                                                                                # RFC 2145 section 3.1 says there can be only one "." and
                                                                                                                                                #   - major and minor numbers MUST be treated as
                                                                                                                                                #      separate integers;
                                                                                                                                                #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
                                                                                                                                                #      turn is lower than HTTP/12.3;
                                                                                                                                                #   - Leading zeros MUST be ignored by recipients.
                                                                                                                                                if len(version_number) != 2:
                                                                                                                                                    raise ValueError
                                                                                                                                                version_number = int(version_number[0]), int(version_number[1])
                                                                                                                                            except (ValueError, IndexError):
                                                                                                                                                self.send_error(400, "Bad request version (%r)" % version)
                                                                                                                                                return False
                                                                                                                                            if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
                                                                                                                                                self.close_connection = 0
                                                                                                                                            if version_number >= (2, 0):
                                                                                                                                                self.send_error(505,
                                                                                                                                                          "Invalid HTTP Version (%s)" % base_version_number)
                                                                                                                                                return False
                                                                                                                                        elif len(words) == 2:
                                                                                                                                            command, path = words
                                                                                                                                            self.close_connection = 1
                                                                                                                                            if command != 'GET':
                                                                                                                                                self.send_error(400,
                                                                                                                                                                "Bad HTTP/0.9 request type (%r)" % command)
                                                                                                                                                return False
                                                                                                                                        elif not words:
                                                                                                                                            return False
                                                                                                                                        else:
                                                                                                                                            self.send_error(400, "Bad request syntax (%r)" % requestline)
                                                                                                                                            return False
                                                                                                                                        self.command, self.path, self.request_version = command, path, version
                                                                                                                                
                                                                                                                                        # 获取头部信息
                                                                                                                                        # Examine the headers and look for a Connection directive
                                                                                                                                        self.headers = self.MessageClass(self.rfile, 0)
                                                                                                                                
                                                                                                                                        conntype = self.headers.get('Connection', "")
                                                                                                                                        if conntype.lower() == 'close':
                                                                                                                                            self.close_connection = 1
                                                                                                                                        elif (conntype.lower() == 'keep-alive' and
                                                                                                                                              self.protocol_version >= "HTTP/1.1"):
                                                                                                                                            self.close_connection = 0
                                                                                                                                        return True
                                                                                                                                    
                                                                                                                                    }:  # An error code has been sent, just exit
                                                                                                                                        return
                                                                                                                                        
                                                                                                                                    # 处理请求
                                                                                                                                    # handler === django.core.servers.basehttp.ServerHandler
                                                                                                                                    handler = ServerHandler(
                                                                                                                                        self.rfile, self.wfile, self.get_stderr(), self.get_environ()
                                                                                                                                    )
                                                                                                                                    {
                                                                                                                                        def __init__(self,stdin,stdout,stderr,environ,
                                                                                                                                            multithread=True, multiprocess=False
                                                                                                                                        ):
                                                                                                                                            self.stdin = stdin # 输入句柄
                                                                                                                                            self.stdout = stdout # 输出句柄
                                                                                                                                            self.stderr = stderr 
                                                                                                                                            self.base_env = environ # 环境变量
                                                                                                                                            self.wsgi_multithread = multithread
                                                                                                                                            self.wsgi_multiprocess = multiprocess
                                                                                                                                    }
                                                                                                                                    
                                                                                                                                    # handler.request_handler === django.core.servers.basehttp.WSGIRequestHandler
                                                                                                                                    handler.request_handler = self      # backpointer for logging
                                                                                                                                    
                                                                                                                                    # !!! django.core.servers.basehttp.ServerHandler.run(self.server.get_app())
                                                                                                                                    # self.server === django.core.servers.basehttp.WSGIServer
                                                                                                                                    # self.server.get_app() == django.core.handlers.wsgi.WSGIHandler
                                                                                                                                    handler.run(self.server.get_app())
                                                                                                                                    {
                                                                                                                                        def run(self, application):
                                                                                                                                            # Invoke the application
                                                                                                                                            # Note to self: don't move the close()!  Asynchronous servers shouldn't
                                                                                                                                            # call close() from finish_response(), so if you close() anywhere but
                                                                                                                                            # the double-error branch here, you'll break asynchronous servers by
                                                                                                                                            # prematurely closing.  Async servers must return from 'run()' without
                                                                                                                                            # closing if there might still be output to iterate over.
                                                                                                                                            try:
                                                                                                                                                # 安装环境变量
                                                                                                                                                # wsgiref.handlers.BaseHandler.setup_environ()
                                                                                                                                                self.setup_environ()
                                                                                                                                                {
                                                                                                                                                    def setup_environ(self):
                                                                                                                                                        # Set up the environment for one request
                                                                                                                                                        # 拷贝系统环境变量
                                                                                                                                                        env = self.environ = self.os_environ.copy()
                                                                                                                                                        # 添加 cgi 变量
                                                                                                                                                        self.add_cgi_vars()
                                                                                                                                                        {
                                                                                                                                                            # SimpleHandler
                                                                                                                                                            def add_cgi_vars(self):
                                                                                                                                                                self.environ.update(self.base_env)
                                                                                                                                                        }
                                                                                                                                                
                                                                                                                                                        env['wsgi.input']        = self.get_stdin()
                                                                                                                                                        env['wsgi.errors']       = self.get_stderr()
                                                                                                                                                        env['wsgi.version']      = self.wsgi_version
                                                                                                                                                        env['wsgi.run_once']     = self.wsgi_run_once
                                                                                                                                                        env['wsgi.url_scheme']   = self.get_scheme()
                                                                                                                                                        env['wsgi.multithread']  = self.wsgi_multithread
                                                                                                                                                        env['wsgi.multiprocess'] = self.wsgi_multiprocess
                                                                                                                                                
                                                                                                                                                        if self.wsgi_file_wrapper is not None:
                                                                                                                                                            env['wsgi.file_wrapper'] = self.wsgi_file_wrapper
                                                                                                                                                
                                                                                                                                                        if self.origin_server and self.server_software:
                                                                                                                                                            env.setdefault('SERVER_SOFTWARE',self.server_software)
                                                                                                                                                }
                                                                                                                                                
                                                                                                                                                # 执行结果放入 self.result
                                                                                                                                                # application === django.core.handlers.wsgi.WSGIHandler
                                                                                                                                                self.result = application(self.environ, self.start_response)
                                                                                                                                                {
                                                                                                                                                    # 调用
                                                                                                                                                    # django.core.handlers.wsgi.WSGIHandler.__call__()
                                                                                                                                                    def __call__(self, environ, start_response):
                                                                                                                                                        # 设置脚本前缀
                                                                                                                                                        set_script_prefix(get_script_name(environ))
                                                                                                                                                        signals.request_started.send(sender=self.__class__, environ=environ)
                                                                                                                                                        
                                                                                                                                                        # 创建 request 对象
                                                                                                                                                        # request_class = django.core.handlers.wsgi.WSGIRequest
                                                                                                                                                        request = self.request_class(environ)
                                                                                                                                                        {
                                                                                                                                                            def __init__(self, environ):
                                                                                                                                                                # 获取 script_name 信息
                                                                                                                                                                script_name = get_script_name(environ)
                                                                                                                                                                # 获取 path_info 信息
                                                                                                                                                                path_info = get_path_info(environ)
                                                                                                                                                                if not path_info:
                                                                                                                                                                    # Sometimes PATH_INFO exists, but is empty (e.g. accessing
                                                                                                                                                                    # the SCRIPT_NAME URL without a trailing slash). We really need to
                                                                                                                                                                    # operate as if they'd requested '/'. Not amazingly nice to force
                                                                                                                                                                    # the path like this, but should be harmless.
                                                                                                                                                                    path_info = '/'
                                                                                                                                                                self.environ = environ
                                                                                                                                                                self.path_info = path_info
                                                                                                                                                                # be careful to only replace the first slash in the path because of
                                                                                                                                                                # http://test/something and http://test//something being different as
                                                                                                                                                                # stated in http://www.ietf.org/rfc/rfc2396.txt
                                                                                                                                                                self.path = '%s/%s' % (script_name.rstrip('/'),
                                                                                                                                                                                       path_info.replace('/', '', 1))
                                                                                                                                                                self.META = environ
                                                                                                                                                                self.META['PATH_INFO'] = path_info
                                                                                                                                                                self.META['SCRIPT_NAME'] = script_name
                                                                                                                                                                self.method = environ['REQUEST_METHOD'].upper()
                                                                                                                                                                self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
                                                                                                                                                                if 'charset' in self.content_params:
                                                                                                                                                                    try:
                                                                                                                                                                        codecs.lookup(self.content_params['charset'])
                                                                                                                                                                    except LookupError:
                                                                                                                                                                        pass
                                                                                                                                                                    else:
                                                                                                                                                                        self.encoding = self.content_params['charset']
                                                                                                                                                                self._post_parse_error = False
                                                                                                                                                                try:
                                                                                                                                                                    content_length = int(environ.get('CONTENT_LENGTH'))
                                                                                                                                                                except (ValueError, TypeError):
                                                                                                                                                                    content_length = 0
                                                                                                                                                                self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
                                                                                                                                                                self._read_started = False
                                                                                                                                                                self.resolver_match = None
                                                                                                                                                        }
                                                                                                                                                        
                                                                                                                                                        # 执行中间件链条,响应 response 对象
                                                                                                                                                        response = self.get_response(request)
                                                                                                                                                        {
                                                                                                                                                            # Setup default url resolver for this thread
                                                                                                                                                            set_urlconf(settings.ROOT_URLCONF)
                                                                                                                                                            
                                                                                                                                                            # ------------ 传入中间件链条,并执行 ------------ 
                                                                                                                                                            response = self._middleware_chain(request)
                                                                                                                                                    
                                                                                                                                                            # This block is only needed for legacy MIDDLEWARE_CLASSES; if
                                                                                                                                                            # MIDDLEWARE is used, self._response_middleware will be empty.
                                                                                                                                                            try:
                                                                                                                                                                # !!! 应用 _response_middleware 类的中间件
                                                                                                                                                                # Apply response middleware, regardless of the response
                                                                                                                                                                for middleware_method in self._response_middleware:
                                                                                                                                                                    # 应用 _response_middleware 类的中间件
                                                                                                                                                                    response = middleware_method(request, response)
                                                                                                                                                                    # Complain if the response middleware returned None (a common error).
                                                                                                                                                                    if response is None:
                                                                                                                                                                        raise ValueError(
                                                                                                                                                                            "%s.process_response didn't return an "
                                                                                                                                                                            "HttpResponse object. It returned None instead."
                                                                                                                                                                            % (middleware_method.__self__.__class__.__name__))
                                                                                                                                                            except Exception:  # Any exception should be gathered and handled
                                                                                                                                                                signals.got_request_exception.send(sender=self.__class__, request=request)
                                                                                                                                                                response = self.handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
                                                                                                                                                            
                                                                                                                                                            
                                                                                                                                                            response._closable_objects.append(request)
                                                                                                                                                            
                                                                                                                                                            # --------- response 对象中有 render 方法 ---------
                                                                                                                                                            # If the exception handler returns a TemplateResponse that has not
                                                                                                                                                            # been rendered, force it to be rendered.
                                                                                                                                                            if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
                                                                                                                                                                response = response.render() # 调用 render 方法
                                                                                                                                                            
                                                                                                                                                            # 响应状态码
                                                                                                                                                            if response.status_code == 404:
                                                                                                                                                                logger.warning(
                                                                                                                                                                    'Not Found: %s', request.path,
                                                                                                                                                                    extra={'status_code': 404, 'request': request},
                                                                                                                                                                )
                                                                                                                                                    
                                                                                                                                                            return response
                                                                                                                                                        }
                                                                                                                                                        # response._handler_class === django.core.handlers.wsgi.WSGIHandler
                                                                                                                                                        response._handler_class = self.__class__
                                                                                                                                                        
                                                                                                                                                        # 响应状态信息
                                                                                                                                                        status = '%d %s' % (response.status_code, response.reason_phrase)
                                                                                                                                                        # 响应头
                                                                                                                                                        response_headers = [(str(k), str(v)) for k, v in response.items()]
                                                                                                                                                        # 在响应头中添加cookie信息
                                                                                                                                                        for c in response.cookies.values():
                                                                                                                                                            response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
                                                                                                                                                        
                                                                                                                                                        # !!! django.core.handlers.wsgi.WSGIHandler.start_response(...) 
                                                                                                                                                        start_response(force_str(status), response_headers)
                                                                                                                                                        {
                                                                                                                                                            def start_response(self, status, headers,exc_info=None):
                                                                                                                                                                # 'start_response()' callable as specified by PEP 333
                                                                                                                                                        
                                                                                                                                                                if exc_info:
                                                                                                                                                                    try:
                                                                                                                                                                        if self.headers_sent:
                                                                                                                                                                            # Re-raise original exception if headers sent
                                                                                                                                                                            raise exc_info[0], exc_info[1], exc_info[2]
                                                                                                                                                                    finally:
                                                                                                                                                                        exc_info = None        # avoid dangling circular ref
                                                                                                                                                                elif self.headers is not None:
                                                                                                                                                                    raise AssertionError("Headers already set!")
                                                                                                                                                        
                                                                                                                                                                assert type(status) is StringType,"Status must be a string"
                                                                                                                                                                assert len(status)>=4,"Status must be at least 4 characters"
                                                                                                                                                                assert int(status[:3]),"Status message must begin w/3-digit code"
                                                                                                                                                                assert status[3]==" ", "Status message must have a space after code"
                                                                                                                                                                if __debug__:
                                                                                                                                                                    for name,val in headers:
                                                                                                                                                                        assert type(name) is StringType,"Header names must be strings"
                                                                                                                                                                        assert type(val) is StringType,"Header values must be strings"
                                                                                                                                                                        assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
                                                                                                                                                                self.status = status
                                                                                                                                                                # !!! 响应头 headers_class === Headers
                                                                                                                                                                self.headers = self.headers_class(headers)
                                                                                                                                                                return self.write
                                                                                                                                                        }
                                                                                                                                                        if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
                                                                                                                                                            response = environ['wsgi.file_wrapper'](response.file_to_stream)
                                                                                                                                                        return response
                                                                                                                                                
                                                                                                                                                }
                                                                                                                                                
                                                                                                                                                # django.core.servers.basehttp.ServerHandler.finish_response()
                                                                                                                                                self.finish_response()
                                                                                                                                                {
                                                                                                                                                    def finish_response(self):
                                                                                                                                                        # Send any iterable data, then close self and the iterable
                                                                                                                                                        # Subclasses intended for use in asynchronous servers will
                                                                                                                                                        # want to redefine this method, such that it sets up callbacks
                                                                                                                                                        # in the event loop to iterate over the data, and to call
                                                                                                                                                        # 'self.close()' once the response is finished.
                                                                                                                                                        try:
                                                                                                                                                            if not self.result_is_file() or not self.sendfile():
                                                                                                                                                                # 处理执行结果 self.result
                                                                                                                                                                for data in self.result:
                                                                                                                                                                    self.write(data)
                                                                                                                                                                    {
                                                                                                                                                                        assert type(data) is StringType,"write() argument must be string"

                                                                                                                                                                        if not self.status:
                                                                                                                                                                            raise AssertionError("write() before start_response()")
                                                                                                                                                                
                                                                                                                                                                        elif not self.headers_sent:
                                                                                                                                                                            # Before the first output, send the stored headers
                                                                                                                                                                            self.bytes_sent = len(data)    # make sure we know content-length
                                                                                                                                                                            self.send_headers()
                                                                                                                                                                            {
                                                                                                                                                                                def send_headers(self):
                                                                                                                                                                                    # Transmit headers to the client, via self._write()
                                                                                                                                                                                    self.cleanup_headers()
                                                                                                                                                                                    self.headers_sent = True
                                                                                                                                                                                    if not self.origin_server or self.client_is_modern():
                                                                                                                                                                                        self.send_preamble()
                                                                                                                                                                                        # 发送 header 数据
                                                                                                                                                                                        self._write(str(self.headers))
                                                                                                                                                                                        {
                                                                                                                                                                                            def _write(self,data):
                                                                                                                                                                                                self.stdout.write(data)
                                                                                                                                                                                                self._write = self.stdout.write
                                                                                                                                                                                        }
                                                                                                                                                                            }
                                                                                                                                                                        else:
                                                                                                                                                                            self.bytes_sent += len(data)
                                                                                                                                                                
                                                                                                                                                                        # 发送 body 数据 
                                                                                                                                                                        # XXX check Content-Length and truncate if too many bytes written?
                                                                                                                                                                        self._write(data)
                                                                                                                                                                        {
                                                                                                                                                                            def _write(self,data):
                                                                                                                                                                                self.stdout.write(data)
                                                                                                                                                                                self._write = self.stdout.write
                                                                                                                                                                        }
                                                                                                                                                                        self._flush()
                                                                                                                                                                        
                                                                                                                                                                    }
                                                                                                                                                                self.finish_content()
                                                                                                                                                        finally:
                                                                                                                                                            self.close()
                                                                                                                                                }
                                                                                                                                            except:
                                                                                                                                                try:
                                                                                                                                                    self.handle_error()
                                                                                                                                                except:
                                                                                                                                                    # If we get an error handling an error, just give up already!
                                                                                                                                                    self.close()
                                                                                                                                                    raise   # ...and let the actual server figure it out.
                                                                                                                                    }
                                                                                                                            }
                                                                                                                        finally:
                                                                                                                            # 完成请求 === django.core.servers.basehttp.WSGIRequestHandler.finish()
                                                                                                                            self.finish()
                                                                                                                            {
                                                                                                                                # SocketServer.StreamRequestHandler
                                                                                                                                def finish(self):
                                                                                                                                    if not self.wfile.closed:
                                                                                                                                        try:
                                                                                                                                            self.wfile.flush()
                                                                                                                                        except socket.error:
                                                                                                                                            # An final socket error may have occurred here, such as
                                                                                                                                            # the local error ECONNABORTED.
                                                                                                                                            pass
                                                                                                                                    self.wfile.close()
                                                                                                                                    self.rfile.close()
                                                                                                                            }
                                                                                                                }
                                                                                                        }
                                                                                                        self.shutdown_request(request)
                                                                                                }
                                                                                            except:
                                                                                                self.handle_error(request, client_address)
                                                                                                self.shutdown_request(request)
                                                                                }
                                                                    finally:
                                                                        self.__shutdown_request = False
                                                                        self.__is_shut_down.set()
                                                            }
                                                        }
                                                    except socket.error as e:
                                                        # Use helpful error messages instead of ugly tracebacks.
                                                        ERRORS = {
                                                            errno.EACCES: "You don't have permission to access that port.",
                                                            errno.EADDRINUSE: "That port is already in use.",
                                                            errno.EADDRNOTAVAIL: "That IP address can't be assigned to.",
                                                        }
                                                        try:
                                                            error_text = ERRORS[e.errno]
                                                        except KeyError:
                                                            error_text = force_text(e)
                                                        self.stderr.write("Error: %s" % error_text)
                                                        # Need to use an OS exit because sys.exit doesn't work in a thread
                                                        os._exit(1)
                                                    except KeyboardInterrupt:
                                                        if shutdown_message:
                                                            self.stdout.write(shutdown_message)
                                                        sys.exit(0)
                                                }
                                        }
                                    }
                                    
                                    if output:
                                        if self.output_transaction:
                                            connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
                                            output = '%s\n%s\n%s' % (
                                                self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()),
                                                output,
                                                self.style.SQL_KEYWORD(connection.ops.end_transaction_sql()),
                                            )
                                        self.stdout.write(output)
                                finally:
                                    if saved_locale is not None:
                                        translation.activate(saved_locale)
                                return output
                            }
                            
                            # 调用父类 execute - end
                        }
                    except Exception as e:
                        if options.traceback or not isinstance(e, CommandError):
                            raise

                        # SystemCheckError takes care of its own formatting.
                        if isinstance(e, SystemCheckError):
                            self.stderr.write(str(e), lambda x: x)
                        else:
                            self.stderr.write('%s: %s' % (e.__class__.__name__, e))
                        sys.exit(1)
                    finally:
                        try:
                            connections.close_all()
                        except ImproperlyConfigured:
                            # Ignore if connections aren't setup at this point (e.g. no
                            # configured settings).
                            pass
                }
        }
    }

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值