用过 Django 的朋友应该最熟悉这三个命令:

python manage.py runserver
python manage.py makemigrations
python manage.py migrate

非常方便,不是吗?那其实,我们也可以自定义这样的命令,来提高我们的开发效率。

今天就来分享如何在 Django 中创建自定义的管理命令。

和 Django 的模版 template 一样,自定义的命令也遵循一定的路径格式。

在每个 app 目录下,新建一个 management/commands 目录,Django 会给目录下的每个 Python 文件注册一个 manage.py 命令,这个命令的名字不以下划线开头。例如:

polls/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
closepoll.py
tests.py
views.py

请注意,上述路径中的 _private.py 不会生效。polls 需要在 ​​settings.py​​​ 中的 INSTALLED_APPS 中注册,​​python manage.py closepoll​​ 才会生效。

接下来说下 closepoll 这个文件的格式。

对 closepoll.py 模块只有一个要求,那就是必须定义 Command 类,该类继承自 BaseCommand 或其子类。

比如像这样:

from django.core.management.base import BaseCommand, CommandError

class Command(BaseCommand):
help = 'Closes the specified poll for voting'

def add_arguments(self, parser):
parser.add_argument('poll_ids', nargs='+', type=int)

def handle(self, *args, **options):
for poll_id in options['poll_ids']:
print(f"closing {poll_id} done.")
#do something here

self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))

通常,主要的处理逻辑会放在 handle 函数里面,在 INSTALLED_APPS 中添加 polls 后,运行一下 ​​python manage.py closepoll 1 2 3​​ 会得到如下结果:

当你使用管理命令并希望提供控制台输出时,你需要 write 至 self.stdout 和 self.stderr,而不是直接 print 至 stdout 和 stderr,这样可以输出多彩的结果。还需要注意的是,你不需要用换行符来结束消息,它会自动添加,除非你指定了 ending 参数:

self.stdout.write("Unterminated line", ending='')

还可以为命令添加可选参数,通过接受额外的命令行选项来删除一个给定的投票,而不是关闭它。这些自定义选项可以在 add_arguments() 方法中添加,比如:

class Command(BaseCommand):
def add_arguments(self, parser):
# Positional arguments
parser.add_argument('poll_ids', nargs='+', type=int)

# Named (optional) arguments
parser.add_argument(
'--delete',
action='store_true',
help='Delete poll instead of closing it',
)

def handle(self, *args, **options):
# ...
if options['delete']:
poll.delete()
# ...

本例中 delete 是由 handle 方法的 options 字典参数传入的,参见 Python 文档查询 argparse,获取更多 add_argument 的用法。

最后的话

自定义管理命令在运行独立脚本命令方面十分有用,也可用于 UNIX 的周期性 crontab 任务,或是 Windows 的定时任务。如果今天的分享有帮助,多谢支持。