编写自定义django-admin命令

应用程序可以使用manage.py注册自己的操作。 例如,您可能需要为要分发的Django应用程序添加manage.py动作。 在这个文档中,我们将为来自tutorialpolls应用程序构建一个自定义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模块将不可用作管理命令。

The closepoll.py module has only one requirement – it must define a class Command that extends BaseCommand or one of its subclasses.

独立的脚本

自定义管理命令对于运行独立脚本或从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_id', nargs='+', type=int)

    def handle(self, *args, **options):
        for poll_id in options['poll_id']:
            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))

注意

When you are using management commands and wish to provide console output, you should write to self.stdout and self.stderr, instead of printing to stdout and stderr directly. 通过使用这些代理,测试自定义命令变得更加容易。 另请注意,您不需要使用换行符结束消息,除非您指定ending参数,否则它将自动添加。

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

新的自定义命令可以使用python manage.py closepoll < poll_id> T0>。

对于每一个方法,handle()方法将一个或多个poll_ids设置为poll.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_id', nargs='+', type=int)

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

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

这个选项(在我们的例子中是delete)在handle方法的选项dict参数中可用。 有关add_argument用法的更多信息,请参阅argparse Python文档。

除了可以添加自定义的命令行选项,所有的management commands都可以接受一些默认的选项,比如--verbosity--traceback

管理命令和语言环境

默认情况下,BaseCommand.execute()方法会停用翻译,因为Django附带的一些命令会执行几个需要使用项目中立的字符串语言的任务(例如,面向用户的内容呈现和数据库填充)。

如果由于某种原因,您的自定义管理命令需要使用固定的语言环境,则应该使用I18N支持代码提供的函数在handle()方法中手动激活和停用它:

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

class Command(BaseCommand):
    ...

    def handle(self, *args, **options):

        # Activate a fixed locale, e.g. Russian
        translation.activate('ru')

        # Or you can activate the LANGUAGE_CODE # chosen in the settings:
        from django.conf import settings
        translation.activate(settings.LANGUAGE_CODE)

        # Your command logic here
        ...

        translation.deactivate()

另一个需要的可能是你的命令只是使用设置中设置的语言环境,Django应该被禁止去激活它。 您可以通过使用BaseCommand.leave_locale_alone选项来实现它。

在处理上述场景时,要考虑到系统管理命令通常必须非常小心在非统一的语言环境中运行,因此您可能需要:

  • 运行命令时,确保USE_I18N设置始终为True
  • 查看您的命令的代码以及在语言环境发生变化时要求行为差异的代码,并评估其对可预测的命令行为的影响。

测试¶ T0>

有关如何测试自定义管理命令的信息可以在testing docs中找到。

覆盖命令

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

换句话说,要覆盖一个命令,新命令必须具有相同的名称,并且其应用程序必须位于INSTALLED_APPS中的覆盖命令的应用程序之前。

第三方应用程序无意中被覆盖的管理命令可以通过在项目的一个应用程序(在INSTALLED_APPS中的第三方应用程序之前订购)中创建一个新命令导入覆盖命令的Command

命令对象

BaseCommand[source]

所有管理命令最终从中得到的基类。

如果你想访问所有的解析命令行参数的机制并找出响应调用的代码,可以使用这个类。如果你不需要改变这种行为,可以考虑使用它的一个subclasses

继承BaseCommand类需要实现handle()方法。

属性¶ T0>

所有的属性都可以在派生类中设置,并可以在BaseCommandsubclasses中使用。

BaseCommand。帮助 T0> ¶ T1>

该命令的简短描述,将在用户运行命令时显示在帮助消息中python manage.py 帮助 <命令> T4> T0>。

BaseCommand。 missing_args_message T0> ¶ T1>

如果您的命令定义了强制性位置参数,则可以自定义在缺少参数的情况下返回的消息错误。 缺省值是由argparse(“太少的参数”)输出的。

BaseCommand。 output_transaction T0> ¶ T1>

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

BaseCommand。 requires_migrations_checks T0> ¶ T1>

布尔型;如果True,则如果磁盘上的迁移集与数据库中的迁移不匹配,则该命令会输出警告。 警告不会阻止命令的执行。 默认值是False

BaseCommand。 requires_system_checks T0> ¶ T1>

布尔型;如果True,则在执行命令之前将检查整个Django项目是否存在潜在的问题。 默认值是True

BaseCommand。 leave_locale_alone T0> ¶ T1>

一个布尔值,用于指示在执行命令期间是否保留设置中设置的区域设置,而不是停用翻译。

默认值是False

如果您决定在自定义命令中更改此选项的值,请确保您知道自己在做什么,只要它创建的数据库内容对语言环境非常敏感,并且此类内容不应包含任何翻译(例如,使用django.contrib.auth权限)激活任何语言环境可能会导致意想不到的效果。 有关更多详细信息,请参阅上面的管理命令和区域设置部分。

BaseCommand。式 T0> ¶ T1>

写入stdoutstderr时有助于创建彩色输出的实例属性。 例如:

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

请参阅Syntax coloring以了解如何修改调色板并查看可用的样式(使用该部分中描述的“角色”的大写版本)。

如果在运行命令时传递--no-color选项,则所有的self.style()调用将返回原始字符串uncolored。

方法¶ T0>

BaseCommand has a few methods that can be overridden but only the handle() method must be implemented.

在子类中实现构造函数

如果在BaseCommand的子类中实现__init__,则必须调用BaseCommand__init__

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ...
BaseCommand。add_arguments(parser)[source]

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

BaseCommand。get_version()[source]

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

BaseCommand。执行* args**选项[source]

尝试执行此命令,根据需要执行系统检查(由requires_system_checks属性控制)。 如果该命令产生一个CommandError,它将被拦截并打印到stderr。

在您的代码中调用管理命令

execute() should not be called directly from your code to execute a command. 改用call_command()

BaseCommand。句柄* args**选项[source]

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

It may return a string which will be printed to stdout (wrapped by BEGIN; and COMMIT; if output_transaction is True).

BaseCommand。check(app_configs=None, tags=None, display_num_errors=False)[source]

使用系统检查框架来检查整个Django项目是否存在潜在的问题。 严重的问题会引发一个CommandError;警告输出到stderr;次要通知输出到标准输出。

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

BaseCommand子类

AppCommand T0> ¶ T1>

一个管理命令,它将一个或多个已安装的应用程序标签作为参数,并对每个应用程序执行一些操作。

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

AppCommand。handle_app_configapp_config** options

app_config执行该命令的操作,该操作将是与命令行上给出的应用程序标签对应的AppConfig实例。

LabelCommand T0> ¶ T1>

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

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

LabelCommand。标签 T0> ¶ T1>

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

LabelCommand。handle_labellabel** options

label执行命令的操作,这将是命令行中给出的字符串。

命令异常

例外 CommandError[source]

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

如果在命令行控制台执行管理命令期间引发此异常,则会将其捕获并转换为恰当的输出流(即stderr)的错误消息。因此,引发这个异常(对错误进行合理的描述)是指示执行命令出现问题的首选方式。

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