django源码(2.0.2)粗解之命令行执行
前言
django的命令行在整个的django web开发中都会经常用到,而且是必须得用到。所以,能够了解下django的命令行实现其实是非常有帮助的。
如果大家比较关心django命令的详细说明和使用,可以查看这里。
命令行执行入口
django通过django-admin.py和manage.py来执行命令,以下是这两个文件的源码:
from django.core import management if __name__ == "__main__":
management.execute_from_command_line()
它们都调用了management模块下的execute_from_command_line()方法。
这个方法是在django/core/management/__init__.py中定义:
def execute_from_command_line(argv=None):
"""Run a ManagementUtility."""
utility = ManagementUtility(argv)
utility.execute()
实现非常简单:生成一个ManagementUtility对象,并让这个对象执行相应的命令行命令。所以主要的工作都是在ManagementUtility这个类中实现的。
ManagementUtility类
python是一门面向的对象的语言,django作为python的一个著名web框架,它所使用当然也是面向对象的思想。所以我们在分析源码的时候应该尽量用面向对象的思想去思考。
ManagementUtility具有3个属性,我们可以从它的__init__函数中看到。
def __init__(self, argv=None):
self.argv = argv or sys.argv[:] # 从传入的参数获得,如果没有传入参数就从sys.argv中去取
self.prog_name = os.path.basename(self.argv[0])
if self.prog_name == '__main__.py':
self.prog_name = 'python -m django'
self.settings_exception = None
self.argv:命令行信息,包括命令和参数
self.prog_name:程序名
self.settings_excepiton:settings的异常信息,发现settings的设置有异常,会将异常信息存在这个变量里面
ManagementUtility主要的方法是execute(),它完成了command执行的所有过程。
1. 我们知道,django的命令行是具有一定的格式的,都是 command subcommand [arguments],arguments有时是可选的。所以execute方法第一步就是获得subcommand,以便确定后续执行什么任务。
try:
subcommand = self.argv[1]
except IndexError:
subcommand = 'help' # Display help if no arguments were given.
这里提一下,为什么不先获取command呢?其实command是系统用来找程序入口的。
2. 用命令解析器CommandParser解析命令行。CommandParser继承了argparse模块的ArgumentParser类,但它只是对ArgumentParser的异常处理进行了加强。
class CommandParser(ArgumentParser):
"""
Customized ArgumentParser class to improve some error messages and prevent
SystemExit in several occasions, as SystemExit is unacceptable when a
command is called programmatically.
"""
def __init__(self, cmd, **kwargs):
self.cmd = cmd
super().__init__(**kwargs) def parse_args(self, args=None, namespace=None):
# Catch missing argument for a better error message
if (hasattr(self.cmd, 'missing_args_message') and
not (args or any(not arg.startswith('-') for arg in args))):
self.error(self.cmd.missing_args_message)
return super().parse_args(args, namespace) def error(self, message):
if self.cmd._called_from_command_line:
super().error(message)
else:
raise CommandError("Error: %s" % message)
3. 解析器解析出了subcommand的arguments,然后fetch_command根据subcommand导入相应的command包并生成相应的command对象,然后调用command对象的print_help方法或者run_from_argv方法去执行相应的命令。
if subcommand == 'help':
if '--commands' in args: # only print the commands only
sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
elif len(options.args) < 1: # print out the usages
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的代码:
def fetch_command(self, subcommand):
"""
Try to fetch the given subcommand, printing a message with the
appropriate command called from the command line (usually
"django-admin" or "manage.py") if it can't be found.
"""
# Get commands outside of try block to prevent swallowing exceptions
commands = get_commands()
try:
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:
klass = load_command_class(app_name, subcommand)
return klass
这里主要用了load_command_class去导入相应的subcommand模块,并生成了一个command类对象。
def load_command_class(app_name, name):
"""
Given a command name and an application name, return the Command
class instance. Allow all errors raised by the import process
(ImportError, AttributeError) to propagate.
"""
module = import_module('%s.management.commands.%s' % (app_name, name))
#print("import %s %s" %(app_name, name))
return module.Command()
我们可以去django/core/management/command/目录下随便找一个command模块看一眼,比如说check.py,每个模块都有一个command类并继承自BaseCommand。上面提到的print_help方法或者run_from_argv方法都是在BaseCommand类中实现。
class Command(BaseCommand):
help = "Checks the entire Django project for potential problems." requires_system_checks = False #...
-------------------------------------------------
以上是我的一点粗浅的理解,如果有觉得不对的地方,请多多指教,非常感谢!
2018-03-21 17:57:17
django源码(2.0.2)粗解之命令行执行的更多相关文章
- [Go] gocron源码阅读-通过第三方cli包实现命令行参数获取和管理
gocron源码中使用的是下面这个第三方包来实现的,下面就单独的拿出来测试以下效果,和官方flag包差不多 go get github.com/urfave/cli package main impo ...
- Kitex源码阅读——脚手架代码是如何通过命令行生成的(一)
前言 Kitex是字节跳动内部的Golang微服务RPC框架,先已开源. Kitex文档:https://www.cloudwego.io/zh/docs/kitex/getting-started/ ...
- Django 源码小剖: URL 调度器(URL dispatcher)
在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 URL. 这是 django url 匹配处理机制的 ...
- Django 源码小剖: 初探中间件(middleware)
因为考虑到文章的长度, 所以 BaseHandler 的展开被推迟了. 在 BaseHandler 中隐藏着中间件的信息, 较常见的 SessionMiddleware 就已经默认安装. BaseH ...
- Django 源码小剖: Django ORM 查询管理器
ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从 ...
- Django 源码小剖: 响应数据 response 的返回
响应数据的返回 在 WSGIHandler.__call__(self, environ, start_response) 方法调用了 WSGIHandler.get_response() 方法, 由 ...
- django源码阅读
最近再看django-bootstrap-toolkit,一直困惑于静态文件的路径问题.所以只能从源码入手了. 从manage.py开始.manage.py 比较简单就几句话. #!/usr/bi ...
- Django 源码小剖: 初探 WSGI
Django 源码小剖: 初探 WSGI python 作为一种脚本语言, 已经逐渐大量用于 web 后台开发中, 而基于 python 的 web 应用程序框架也越来越多, Bottle, Djan ...
- 【集合框架】JDK1.8源码分析之ArrayList详解(一)
[集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...
随机推荐
- 如何提高PHP执行效率
用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说 ...
- Densely Connected Convolutional Networks 论文阅读
毕设终于告一段落,传统方法的视觉做得我整个人都很奔溃,终于结束,可以看些搁置很久的一些论文了,嘤嘤嘤 Densely Connected Convolutional Networks 其实很早就出来了 ...
- 洛谷P2341受欢迎的牛
传送门啦 这是一个tarjan强连通分量与出度结合的例题. 先明确一下题意,如果这个点(缩点之后的)没有出度,这个点才能成为明星牛(明星牛的定义是:所有牛都喜欢他才可以). 由于我们进行了缩点,所以我 ...
- sqlserver sp_spaceused用法
sp_spaceused显示行数.保留的磁盘空间以及当前数据库中的表所使用的磁盘空间,或显示由整个数据库保留和使用的磁盘空间. 语法sp_spaceused [[@objname =] 'objnam ...
- MySQL学习笔记:like和regexp的区别
一.like关键字 like有两个模式:_和% _:表示单个字符,用来查询定长的数据 select name from table where name like '陈__'; %:表示0个或多个任意 ...
- SqlServr性能优化性能之层次结构(十五)
1.添加根节点: hierarchyid GetRoot()方法 --创建数据库 create table Employeeh(EmployeeID int,Name varchar(500),Ma ...
- .gitignore文件如何编写?
.gitignore文件即 项目中不需要被追踪(track)且上传到git系统的文件 <1>忽略文件的原则 a.忽略操作系统自动生成的文件,比如缩略图等 b.忽略编译生成的中间文件.可执行 ...
- 多线程-TaskExecutor-使用Demo
BasicExecute.java package com.jef.executeTest; public abstract class BasicExecute extends Thread { @ ...
- 【LOJ】#2722. 「NOI2018」情报中心
https://loj.ac/problem/2722 题解 考场上想了60分,但是由于自己不知道在怎么zz,我连那个ai<bi都没看到,误以为出题人没给lca不相同的部分分,然后觉得lca不同 ...
- 003 JTA的使用与理解
一:认识JTA 1.介绍 事物的ACID. 事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity ).一致性 ( Consistency ).隔离性 ( Isolat ...