如何创建自定义 django-admin 命令

应用程序可以用注册自己的操作 manage.py . 例如,您可能希望添加 manage.py 为您正在分发的django应用程序执行操作。在本文档中,我们将创建一个自定义 closepoll 命令 polls 应用程序来自 tutorial .

要执行此操作,请添加一个 management/commands 目录添加到应用程序。Django将注册一个 manage.py 命令,用于该目录中名称不以下划线开头的每个Python模块。例如:

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

在这个例子中, closepoll 命令将可用于包括 polls 应用于 INSTALLED_APPS .

这个 _private.py 模块不能作为管理命令使用。

这个 closepoll.py 模块只有一个需求——它必须定义一个类 Command 延伸的 BaseCommand 或其中之一 subclasses .

独立脚本

自定义管理命令对于运行独立脚本或从Unix crontab或Windows计划任务控制面板定期执行的脚本特别有用。

要实现命令,请编辑 polls/management/commands/closepoll.py to look like this:

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)
            )

备注

当您使用管理命令并希望提供控制台输出时,应该写入 self.stdoutself.stderr 而不是打印到 stdoutstderr 直接。通过使用这些代理,测试自定义命令变得更加容易。还要注意,您不需要以换行符结束消息,除非您指定 ending 参数::

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

可以使用调用新的自定义命令 python manage.py closepoll <poll_ids> .

这个 handle() 方法需要一个或多个 poll_idspoll.openedFalse 对于每一个。如果用户引用了任何不存在的投票,则 CommandError 提高了。这个 poll.opened 属性不存在于 tutorial 并被添加到 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方法的选项dict参数中可用。见 argparse 关于python文档的更多信息 add_argument 用法。

除了能够添加自定义命令行选项外,所有 management commands 可以接受一些默认选项,例如 --verbosity--traceback .

管理命令和区域设置

默认情况下,管理命令使用当前活动的区域设置执行。

如果出于某种原因,自定义管理命令必须在没有活动区域设置的情况下运行(例如,为了防止翻译的内容插入数据库),请使用 @no_translations 装饰你的 handle() 方法:

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


class Command(BaseCommand):
    ...

    @no_translations
    def handle(self, *args, **options):
        ...

由于转换停用需要访问配置的设置,因此修饰符不能用于没有配置的设置而工作的命令。

测试

有关如何测试自定义管理命令的信息,请参见 testing docs .

覆盖命令

Django注册内置命令,然后在 INSTALLED_APPS 反过来。在搜索过程中,如果命令名与已注册的命令重复,则新发现的命令将覆盖第一个命令。

换句话说,要重写命令,新命令必须具有相同的名称,并且其应用程序必须在重写命令的应用程序in之前 INSTALLED_APPS .

通过在项目的某个应用程序中创建新命令(在第三方应用程序之前 INSTALLED_APPS )哪个进口的 Command 覆盖的命令。

命令对象

class BaseCommand[源代码]

所有管理命令最终从中派生的基类。

如果希望访问解析命令行参数并计算响应中要调用的代码的所有机制,请使用此类;如果不需要更改任何该行为,请考虑使用 subclasses .

子类化 BaseCommand 类要求您实现 handle() 方法。

属性

所有属性都可以在派生类中设置,并且可以在 BaseCommandsubclasses .

BaseCommand.help

命令的简短描述,当用户运行该命令时,将在帮助消息中打印。 python manage.py help <command> .

BaseCommand.missing_args_message

如果命令定义了强制位置参数,则可以自定义在缺少参数的情况下返回的消息错误。默认值输出方式为 argparse (参数太少)。

BaseCommand.output_transaction

一个布尔值,指示命令是否输出SQL语句;如果 True ,输出将自动包装为 BEGIN;COMMIT; . 默认值为 False .

BaseCommand.requires_migrations_checks

布尔函数 True ,如果磁盘上的迁移集与数据库中的迁移不匹配,该命令将打印一条警告。警告不会阻止命令执行。默认值为 False .

BaseCommand.requires_system_checks

标签的列表或元组,例如 [Tags.staticfiles, Tags.models] 。系统检查 registered in the chosen tags 将在执行该命令之前检查是否有错误。它的价值 '__all__' 可用于指定应执行所有系统检查。默认值为 '__all__'

BaseCommand.style

一个实例属性,在写入时帮助创建彩色输出 stdoutstderr . 例如::

self.stdout.write(self.style.SUCCESS("..."))

语法颜色标记 了解如何修改调色板和查看可用样式(使用该部分中描述的“角色”的大写版本)。

如果你通过 --no-color 运行命令时的选项,全部 self.style() 调用将返回未着色的原始字符串。

BaseCommand.suppressed_base_arguments

帮助输出中要取消显示的默认命令选项。这应该是一组选项名称(例如 '--verbosity' )。仍然传递取消显示的选项的缺省值。

方法

BaseCommand 有几个方法可以被重写,但只有 handle() 必须实现方法。

在子类中实现构造函数

如果你实施 __init__ 在你的子类 BaseCommand ,你必须调用 BaseCommand__init__ ::

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ...
BaseCommand.create_parser(prog_name, subcommand, **kwargs)[源代码]

返回A CommandParser 实例,它是 ArgumentParser 为Django定制的子类。

您可以通过重写此方法并调用 super() 具有 kwargs 属于 ArgumentParser 参数。

BaseCommand.add_arguments(parser)[源代码]

用于添加分析器参数以处理传递给命令的命令行参数的入口点。自定义命令应重写此方法以添加命令接受的位置参数和可选参数。调用 super() 直接子类化时不需要 BaseCommand .

BaseCommand.get_version()[源代码]

返回django版本,该版本对于所有内置django命令都应该是正确的。用户提供的命令可以重写此方法以返回自己的版本。

BaseCommand.execute(*args, **options)[源代码]

尝试执行此命令,并根据需要执行系统检查(由 requires_system_checks 属性)。如果该命令引发 CommandError ,它被截获并打印到 stderr

在代码中调用管理命令

execute() 不应直接从代码中调用以执行命令。使用 call_command() 相反。

BaseCommand.handle(*args, **options)[源代码]

命令的实际逻辑。子类必须实现此方法。

它可以返回一个字符串,该字符串将被打印到 stdout (被包) BEGIN;COMMIT; 如果 output_transactionTrue

BaseCommand.check(app_configs=None, tags=None, display_num_errors=False)[源代码]

使用系统检查框架检查整个Django项目是否存在潜在问题。严重的问题作为一种 CommandError ;警告输出到 stderr ;次要通知输出到 stdout

如果 app_configstags 都是 None ,执行所有系统检查。 tags 可以是支票标签列表,例如 compatibilitymodels .

BaseCommand 子类

class AppCommand

一种管理命令,它以一个或多个已安装的应用程序标签作为参数,并对每一个标签进行处理。

而不是执行 handle() ,子类必须实现 handle_app_config() ,将为每个应用程序调用一次。

AppCommand.handle_app_config(app_config, **options)

执行命令的操作 app_config ,这将是一个 AppConfig 与命令行上给定的应用程序标签相对应的实例。

class LabelCommand

一种管理命令,它在命令行上接受一个或多个任意参数(标签),并对它们中的每一个做一些事情。

而不是执行 handle() ,子类必须实现 handle_label() ,每个标签调用一次。

LabelCommand.label

描述传递给命令的任意参数的字符串。该字符串用于命令的用法文本和错误消息中。默认为 'label' .

LabelCommand.handle_label(label, **options)

执行命令的操作 label ,它将是命令行上给定的字符串。

命令异常

exception CommandError(returncode=1)[源代码]

指示执行管理命令时出现问题的异常类。

如果此异常是在从命令行控制台执行管理命令期间引发的,则它将被捕获并转换成打印得很好的错误消息发送到适当的输出流(即, stderr );因此,引发此异常(带有对错误的合理描述)是指示命令执行过程中出现错误的首选方式。它接受可选的 returncode 参数自定义管理命令退出时的退出状态,使用 sys.exit()

如果从代码到调用管理命令 call_command() ,需要时由您来捕获异常。