编写自定义 django-admin
命令¶
应用程序可以用 manage.py
注册自己的动作。例如,你可能想为你正在分发的 Django 应用添加一个 manage.py
动作。在本文档中,我们将为 教程 中的 polls
应用程序构建一个自定义的 closepoll
命令。
要做到这一点,将一个 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
在这个例子中,closepoll
命令将提供给任何在 INSTALLED_APPS
中包含 polls
应用程序的项目。
_private.py
模块将不会作为管理命令使用。
closepoll.py
模块只有一个要求——必须定义 Command
类,该类继承自 BaseCommand
或其 子类。
独立的脚本
自定义管理命令在运行独立脚本命令方面十分有用,也可用于 UNIX 的周期性 crontab 任务,或是 Windows 的定时任务。
要实现该命令,请编辑 polls/management/commands/closepoll.py
如下:
from django.core.management.base import BaseCommand, CommandError
from polls.models import Question as Poll
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"]:
try:
poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise CommandError('Poll "%s" does not exist' % poll_id)
poll.opened = False
poll.save()
self.stdout.write(
self.style.SUCCESS('Successfully closed poll "%s"' % poll_id)
)
Note
当你使用管理命令并希望提供控制台输出时,你需要 write 至 self.stdout
和 self.stderr
,而不是直接 print 至 stdout
和 stderr
。利用这些代理,测试自定义命令会更方便。还需要注意的是,你不需要用换行符来结束消息,它会自动添加,除非你指定了 ending
参数:
self.stdout.write("Unterminated line", ending="")
这个新的自定义命令能用 python manage.py closepoll <poll_ids>
调用。
handle()
方法接受一个或多个 poll_ids
,并将每个 poll.opened
设置为 False
。若用户传入了不存在的 polls,将会抛出 CommandError
。教程 中不存在 poll.opened
属性,只是这里为了本例添加至 polls.models.Question
的。
接受可选参数¶
同样的 closepoll
可以很容易地修改,通过接受额外的命令行选项来删除一个给定的投票,而不是关闭它。这些自定义选项可以在 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
的用法。
为了能添加自定义命令选项,所以的 管理命令 都能接受一些默认选项,例如 --verbosity
和 --traceback
。
管理命令和本地化¶
默认情况下,管理命令以当前活动的 locale 执行。
如果由于某些原因,你的自定义管理命令必须在没有活动的 locale 的情况下运行(例如,为了防止翻译的内容被插入数据库),请在你的 handle()
方法上使用 @no_translations
装饰器停用翻译:
from django.core.management.base import BaseCommand, no_translations
class Command(BaseCommand):
...
@no_translations
def handle(self, *args, **options): ...
由于禁用翻译需要使用配置文件,故装饰器不能用于那些不加载配置文件的命令。
测试¶
关于如何测试自定义管理命令的内容可在 测试文档 中找到。
覆盖命令¶
Django 先注册内置命令,然后按相反的顺序在 INSTALLED_APPS
查找命令。在查找时,如果一个命令和已注册的命令重名,这个新发现的命令会覆盖第一个命令。
换句话说,为了覆盖一个命令,新命令必须有同样的名字并且它的 app 在 INSTALLED_APPS
中必须排在被覆盖命令 app 的前面。
第三方应用提供的管理命令若被不小心重写,能通过在你项目中的某个应用(在 INSTALLED_APPS
配置在第三方应用之前)创建新命令的方式为其取个别名,另其能被调用。这个应用需要导入被重写的 Command
。
命令对象¶
所有管理命令最终派生的基类。
如果你想处理解析命令行参数,决定调用什么代码的过程,使用这个类。如果你不需要改变任何行为,考虑直接使用它的某个 子类。
继承 BaseCommand
要求你重写 handle()
方法。
属性¶
能被你派生的子类设置的,且能被 BaseCommand
的 子类 使用的属性。
- BaseCommand.help¶
命令简介,当用户运行命令
python manage.py help <command>
时包含在打印的帮助信息内。
- BaseCommand.missing_args_message¶
如果你的命令定义了必须的位置参数,你可以在缺失参数时返回自定义错误消息。默认输出由
argparse
打印("too few arguments")。
- BaseCommand.output_transaction¶
一个布尔值,决定命令是否暑输出 SQL 语句;若为
True
,输出内容会自动以BEGIN;
和COMMIT;
包裹。默认值为False
。
- BaseCommand.requires_migrations_checks¶
一个布尔值;若为
True
,命令会在硬盘上存储的 migrations 与 数据库中的不一致时打印警告。警告不会阻止命令执行。默认值为False
。
- BaseCommand.requires_system_checks¶
一个标签的列表或元组,例如
[Tags.staticfiles, Tags.models]
。系统会在执行命令 registered in the chosen tags 之前检查是否有错误。值'__all__'
可用于指定应执行所有系统检查。 默认值为'__all__'
。
- BaseCommand.style¶
一个实例属性,用于向
stdout
或stderr
输出彩色内容。例如:self.stdout.write(self.style.SUCCESS("..."))
参考 语法着色 了解如何修改调色板与现成的样式(使用本节介绍的大写字母版本的 "roles")。
如果运行命令时传递了
--no-color
选项,所有的self.style()
调用会返回未染色的原始字符串。
- BaseCommand.suppressed_base_arguments¶
要在帮助输出中取消显示的默认命令选项。这应该是一个选项名称的集合(例如,
'--verbosity'
)。取消显示的选项仍然传递其默认值。
方法¶
BaseCommand
有很多方法可供重写,不过仅有 handle()
是必须实现的。
子类中实现构造器
若 BaseCommand
的子类实现了 __init__
方法,那么就必须调用 BaseCommand
的 __init__
:
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ...
- BaseCommand.create_parser(prog_name, subcommand, **kwargs)[source]¶
返回一个
CommandParser
实例,它是ArgumentParser
的子类,包含一些针对 Django 的个性化设计。你可以自定义这个实例,通过重写此方法,并为
super()
方法传入值为ArgumentParser
的kwargs
参数。
- BaseCommand.add_arguments(parser)[source]¶
添加命令行转换参数的入口,用于处理传给命令行的参数。自定义命令需要重写此方法,并同时添加命令接受的位置参数和可选参数。直接使用
BaseCommand
的子类时无需调用super()
。
- BaseCommand.execute(*args, **options)[source]¶
尝试执行此命令,根据
requires_system_checks
属性控制是否需要执行系统检查。如果命令引发CommandError
,它将被拦截并打印到stderr
。
在你的代码中调用管理命令
执行命令时,不要从代码直接调用 execute()
方法。而是使用 call_command()
。
- BaseCommand.handle(*args, **options)[source]¶
命令的实际逻辑处理。子类必须实现此方法。
此方法可能会返回一个字符串,输出至
stdout
(若output_transaction
为True
,则由BEGIN;
和COMMIT
包裹)。
- BaseCommand.check(app_configs=None, tags=None, display_num_errors=False, include_deployment_checks=False, fail_level=checks.ERROR, databases=None)[source]¶
使用系统检查框架来检查整个 Django 项目中的潜在问题。严重的问题将作为
CommandError
引发;警告将输出到stderr
;较小的通知将输出到stdout
。如果
app_configs
和tags
都是None
,则执行除了部署和数据库相关检查之外的所有系统检查。tags
可以是一个检查标签的列表,比如compatibility
或models
。你可以传递
include_deployment_checks=True
以执行部署检查,并在databases
中传递数据库别名列表以对其运行数据库相关检查。
BaseCommand
的子类¶
- class AppCommand¶
管理命令接受一个或多个应用标签参数,并对每项应用做某些事。
子类必须实现 handle_app_config()
,而不是 handle()
。此方法会为每个应用调用一次。
- AppCommand.handle_app_config(app_config, **options)¶
为
app_config
运行命令,这会是AppConfig
的实例,并指向命令行给定的应用标签。
- class LabelCommand¶
一个管理命令,从命令行接受一个或任意多个参数(labels),并针对每项做些事情。
子类必须实现 handle_label()
,而不是 handle()
。此方法会为每个应用调用一次。
- LabelCommand.label¶
一个字符串,介绍了传递给命令的任意多个参数。此字符串用于命令的用法文本和错误消息。默认为
'label'
。
- LabelCommand.handle_label(label, **options)¶
运行
label
指定的命令动作,由命令行传入的字符串指定。
命令异常¶
异常类说明在运行管理命令时出错了。
如果在从命令行控制台执行管理命令期间引发此异常,它将被捕获并转换为适当输出流(即 stderr
)上的精美打印的错误消息;因此,引发此异常(附带一个合理的错误描述)是指示命令执行出现问题的首选方式。它接受可选的 returncode
参数,以自定义管理命令退出时使用的退出状态,使用 sys.exit()
。
如果管理命令是由 call_command()
调用的,是否捕获异常取决于你。