为了提高自己的编程水平,决定阅读一个大型的开源框架,选了好久在flask和Django最终还是选择Django,主要Django相对于flask来说还是相对比较容易理解的

阅读准备

  • 克隆项目
    git clone https://github.com/django/django
  • 找到最开始的tag,然后checkout它,这个方法是我看Flask实战书籍作者推荐的开源项目阅读方式,因为一开始的代码量比较少,可以先看最初的版本来整体了解框架的架构,熟悉之后再阅读最新的tag

阅读计划

  • 阅读源码框架不能随便读,也要带有目的的读,我采用的方法是先是阅读启动的命令相关的代码,再阅读常用api的实现,最后阅读数据库如何处理部分.

源码初探

  • django manange.py runserver命令源码实现

核心代码


    def execute(self):
        """
        Given the command-line arguments, figure out which subcommand is being
        run, create a parser appropriate to that command, and run it.
        """
        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(usage='%(prog)s subcommand [options] [args]', add_help=False, allow_abbrev=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:
            settings.INSTALLED_APPS
        except ImproperlyConfigured as exc:
            self.settings_exception = exc
        except ImportError 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:
                    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(dict)
                    apps.app_configs = {}
                    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()

        self.autocomplete()

        if subcommand == 'help':
            if '--commands' in args:
                sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
            elif not options.args:
                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).run_from_argv(self.argv)

源码解析

核心fetch_command()函数根据输入的subcomand 获取对应命令模块,run_argv()先进行预处里,进行一些默认设置操作,然后每个不同的命令模块具体实现都实现了handle函数,这里有点Java的味道了,然后run_args调用self.handle(args,*kwargs),获取不同命令的输出,这样就完成了django的命令的架构,可以看到实现方式是非常的巧妙.

最后修改:2021 年 12 月 11 日
如果觉得我的文章对你有用,请随意赞赏