Django扩展自定义manage命令
使用django开发,对python manage.py ***命令模式肯定不会陌生。比较常用的有runserver,migrate。。。
本文讲述如何自定义扩展manage命令。
1、源码分析
manage.py文件是通过django-admin startproject project_name生成的。
1)manage.py的源码
a)首先设置了settings文件,本例中CIServer指的是project_name。
b)其次执行了一个函数django.core.management.execute_from_command_line(sys.argv),这个函数传入了命令行参数sys.argv
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CIServer.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and available "
"on your PATH environment variable? Did you forget to activate a "
"virtual environment?"
)
execute_from_command_line(sys.argv)
2)execute_from_command_line
里面调用了ManagementUtility类中的execute方法
def execute_from_command_line(argv=None):
"""
A simple method that runs a ManagementUtility.
"""
utility = ManagementUtility(argv)
utility.execute()
在execute中主要是解析了传入的参数sys.argv,并且调用了get_command()
3)get_command
def get_commands():
"""
Returns a dictionary mapping command names to their callback applications.
This works by looking for a management.commands package in django.core, and
in each installed application -- if a commands package exists, all commands
in that package are registered.
Core commands are always included. If a settings module has been
specified, user-defined commands will also be included.
The dictionary is in the format {command_name: app_name}. Key-value
pairs from this dictionary can then be used in calls to
load_command_class(app_name, command_name)
If a specific version of a command must be loaded (e.g., with the
startapp command), the instantiated module can be placed in the
dictionary in place of the application name.
The dictionary is cached on the first call and reused on subsequent
calls.
"""
commands = {name: 'django.core' for name in find_commands(upath(__path__[0]))}
if not settings.configured:
return commands
for app_config in reversed(list(apps.get_app_configs())):
path = os.path.join(app_config.path, 'management')
commands.update({name: app_config.name for name in find_commands(path)})
return commands
get_command里遍历所有注册的INSTALLED_APPS路径下的management寻找(find_commands)用户自定义的命令。
def find_commands(management_dir):
"""
Given a path to a management directory, returns a list of all the command
names that are available.
Returns an empty list if no commands are defined.
"""
command_dir = os.path.join(management_dir, 'commands')
# Workaround for a Python 3.2 bug with pkgutil.iter_modules
sys.path_importer_cache.pop(command_dir, None)
return [name for _, name, is_pkg in pkgutil.iter_modules([npath(command_dir)])
if not is_pkg and not name.startswith('_')]
可以发现并注册的命令是commands目录下不以"_"开头的文件名。
4)load_command_class
将命令文件***.py中的Command类加载进去。
def load_command_class(app_name, name):
"""
Given a command name and an application name, returns the Command
class instance. All errors raised by the import process
(ImportError, AttributeError) are allowed to propagate.
"""
module = import_module('%s.management.commands.%s' % (app_name, name))
return module.Command()
5)Command类
Command类要继承BaseCommand类,其中很多方法,一定要实现的是handle方法,handle方法是命令实际执行的代码。
2、如何实现自定义命令
根据上面说的原理,我们只需要在app目录中建立一个目录management,并且在下面建立一个目录叫commands,下面增加一个文件,叫hello.py即可。
要注意一下几点
1)说是目录,其实应该是包,所以在management下面和commands下面都要添加__init__.py。
2)app一定要添加在INSTALLED_APPS中,不然命令加载不到。
应该是这样的
在hello.py中实现命令的具体内容
#-*- coding:utf-8 -*-
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
'-n',
'--name',
action='store',
dest='name',
default='close',
help='name of author.',
)
def handle(self, *args, **options):
try:
if options['name']:
print 'hello world, %s' % options['name']
self.stdout.write(self.style.SUCCESS('命令%s执行成功, 参数为%s' % (__file__, options['name'])))
except Exception, ex:
self.stdout.write(self.style.ERROR('命令执行出错'))
执行方式
python manage.py hello -n kangaroo
hello world, kangaroo
命令hello.py执行成功,参数为kangaroo
- ubuntu上安装Apache2+ModSecurity及自定义WAF规则
- C++中关于指针初始化和使用NULL的理解
- ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示(优化篇)
- (虚)继承类的内存占用大小
- Linux服务器数据定期同步和备份方式
- Android组件化搭建
- ECMAScript 6 入门简介
- RxJava2 实战知识梳理(2) - 计算一段时间内数据的平均值
- 用了Docker,妈妈再也不担心我的软件安装了 - 基础篇
- 适配器模式(Adapter)
- 敞开的地狱之门:Kerberos协议的滥用
- CY7C68013A的一点总结
- RxJava2 实战(1) - 后台执行耗时操作,实时通知 UI 更新
- AutoIt木马又一发:暗藏神秘照片
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- console.log的那件事
- Codeforces Round #668 (Div. 2)A-D
- nodejs源码解析之udp服务器
- LeetCode | 35.搜索插入位置
- Redis | 源码阅读 —— 字符串
- 一个小白的角度看JavaScript Promise 完整指南
- 教会舍友玩 Git (再也不用担心他的学习)
- Python极简入门:数据类型、条件语句、循环语句、异常处理
- 手把手带你入门Python爬虫Scrapy
- 工作中巧用了这几个设计模式重构代码,女同事直呼666
- SourceMap知多少:介绍与实践
- (实战)Node.js 实现抢票小工具&短信通知提醒
- 目标检测 | Anchor free之CenterNet深度解析
- C++第二章 变量与基本类型
- springboot2结合mybatis拦截器实现主键自动生成