我们在使用Django的时候用到很多命令,比如启动服务器的 runserver
同步数据库的 migrate
等等这些都是 Django内置的,同时Django也提供了自定义命令的方法。
需求
自定义一个命令,输出 hello world
1.创建项目
创建一个测试项目,Cmds和应用customCMD,项目结构如下:
然后再在应用目录下创建一个management目录,该目录下在创建一个commands目录, 目录下创建一个 say.py
导入 from django.core.management.base import BaseCommand
# -*- coding:utf-8 -*- from django.core.management.base import BaseCommand # 必须继承BaseCommand class Command(BaseCommand): # 重写handle方法 def handle(self, *args, **options): print('hello world')
测试命令是否添加成功。
打开终端 python3 manage.py --help
我们发现自定义的命令 say
已经添加成功
[customCMD] say
接着我们测试一下这个命令 python3 manage.py say
$ python3 manage.py say hello world
3.添加帮助说明
# -*- coding:utf-8 -*- from django.core.management.base import BaseCommand class Command(BaseCommand): # 添加帮助说明 help = '此命令输入hello world' def handle(self, *args, **options): print('hello world')
然后输入 python3 manage.py say --help
已经有了帮助说明。
4.添加参数
在使用runserver命令的时候我们可以指定端口和地址,这是命令的参数,我们也可以给自己自定义的命令添加参数
from django.core.management.base import BaseCommand class Command(BaseCommand): help = '此命令输入hello world' # 重写 注册参数 def add_arguments(self, parser): parser.add_argument('word', type=str) def handle(self, *args, **options): # 获取参数 print(options['word'])
python3 manage.py say 你好 你好
命令格式 python3 manage.py 自定义命令 <参数列表>
5.Django如何处理命令的
再项目跟目录有个 manage.py
def main(): # 程序入口 # 设置环境变量, 将setting.py中的设值配置好 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Cmds.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: 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?" ) from exc # 解析命令 execute_from_command_line(sys.argv) if __name__ == '__main__': main()
execute_from_command_line()方法
def execute_from_command_line(argv=None): """Run a ManagementUtility.""" utility = ManagementUtility(argv) utility.execute()
ManagementUtility()将解析参数,最终会执行到 get_commands()
@functools.lru_cache(maxsize=None) def get_commands(): # 查找命令 commands = {name: 'django.core' for name in find_commands(__path__[0])} if not settings.configured: return commands for app_config in reversed(list(apps.get_app_configs())): # 查找每一个app目录下的management目录 path = os.path.join(app_config.path, 'management') commands.update({name: app_config.name for name in find_commands(path)}) return commands
find_commands()查找commands下的所有文件并且不能以下划线开头
def find_commands(management_dir): command_dir = os.path.join(management_dir, 'commands') return [name for _, name, is_pkg in pkgutil.iter_modules([command_dir]) if not is_pkg and not name.startswith('_')]
这样命令就配置完成了。
load_command_class()加载命令
def load_command_class(app_name, name): module = import_module('%s.management.commands.%s' % (app_name, name)) return module.Command()