Django(三)runserver 命令源码分析

时间:2021-08-27 19:18:32

应用环境

  • windows7
  • pycharm2018 profession
  • python3.6
  • django2.0

我们在pycharm 启动django项目时,常常有这么一个命令操作:

  • python manage.py runserver

 这里的意思是执行python命令,传入的参数为 manage.py runserver。这两个参数就会被保存到sys.argv 列表中。如下,新建一个demo.py

import sys


print('hello sys.argv')
print(type(sys.argv))
for arg in sys.argv:
    print(arg)

在terminal窗口执行 python demo.py runserver  #  循环遍历sys.argv 输出参数

Django(三)runserver 命令源码分析

PS:这里解释sys.argv 是因为在manage.py中,会用到。

打开我们的manage.py文件,可以看到,这里调用的是:

  • execute_from_command_line(sys.argv)

可以看到这里传入的就是我们执行python 命令传入的参数(这里是manage.py runserver)。

我们进入到 execute_from_command_line 函数,可以看到的是执行

  • utility.execute()

在execute这个函数中有这么一行代码,读取子命令,也即是读取sys.argv列表中第二个元素runserver,如下图

Django(三)runserver 命令源码分析

同时,在execute函数中,我们需要重点关注的是最后这一行代码:

  • self.fetch_command(subcommand).run_from_argv(self.argv)

这里传入的上面的读取的子命令sys.argv[1] 以及self.argv(这里的self.argv 是在构造函数中传入的sys.argv)。

Django(三)runserver 命令源码分析

我们进入到 fetch_command 函数,这里最后返回的一个Command class instance 。也就是说 

  • self.fetch_command(subcommand).run_from_argv(self.argv) 

这行代码的意思是 执行返回的实体类必然包含 run_from_argv函数。

在fetch_command中,最终调用的是

  • import_module('%s.management.commands.%s' % (app_name, name))

这里的注释:

Given a command name and an application name, return the Command
class instance.

通过名字返回实例,这里类似net中IL编程:动态导入(动态生成程序集)【这是本篇博文的重点】。
通过:
print('%s.management.commands.%s' % (app_name, name))
我们发现动态导入的实例是:
  • django.contrib.staticfiles.management.commands.runserver

而我们的 import_module 函数最终执行的也是python标准库 importlib下importlib._bootstrap中的gcd_import。如图:

Django(三)runserver 命令源码分析

通过上面的分析,我们知道最终执行的是模块:

  • django.contrib.staticfiles.management.commands.runserver

下的run_from_argv 函数。

我们打开runserver.py文件,也确是没有找到该函数,而在其父类中找到:

Django(三)runserver 命令源码分析

从上图看出,这个函数最终执行的是execute函数。而在execute中最终执行却又是:

  • output = self.handle(*args, **options)

这里的handle是:

    def handle(self, *args, **options):
        """
        The actual logic of the command. Subclasses must implement
        this method.
        """
        raise NotImplementedError('subclasses of BaseCommand must provide a handle() method')

我们从注释可以知道,这个方法需要由子类实现的,也即最后,最后,最后执行的runserver中handle函数。

分析到这里,已基本很明了,最终执行的是在本地的8000端口启动一个socketserver监听程序。

 

分析所得:

  • get到python如何进行动态的导入
  • sys.argv 存储了全局中输入参数
  • sys.moduls注册了程序运行已经导入模块
  • if 赋值的优雅写法 subcommand = 'runserver'  if 1== 'condition' else 'hello'

这里一行代码等价于这么写:

if 1=='condition' :

    subcommand = 'runserver'

else:

  subcommand = 'hello'

这里一行代码搞定,看起来不错。

 

希望这篇文字可以帮助到大家。刚接触python,若是有不对的地方,欢迎指出。谢谢。