django 1.8 官方文档翻译: 6-4-2 编写自定义的django-admin命令

编写自定义的django-admin命令

应用能够经过manage.py注册它们本身的动做。例如,你可能想为你正在发布的Django应用添加一个manage.py动做。在本页文档中,咱们将为教程中的 polls应用构建一个自定义的 closepoll命令。html

要作到这点,只需向该应用添加一个management/commands目录。Django将为该目录中名字没有如下划线开始的每一个Python模块注册一个manage.py命令。例如:python

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

在Python 2上,请确保managementmanagement/commands两个目录都包含__init__.py 文件,不然将检测不到你的命令。数据库

在这个例子中,closepoll命令对任何项目均可使用,只要它们在INSTALLED_APPS里包含polls应用。django

_private.py将不能够做为一个管理命令使用。app

closepoll.py模块只有一个要求 – 它必须定义一个Command类并扩展自BaseCommand或其 子类。框架

独立的脚本函数

自定义的管理命令主要用于运行独立的脚本或者UNIX crontab和Windows周期任务控制面板周期性执行的脚本。测试

要实现这个命令,需将polls/management/commands/closepoll.py编辑成这样:ui

from django.core.management.base import BaseCommand, CommandError
from polls.models import 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('Successfully closed poll "%s"' % poll_id)
Changed in Django 1.8:

在Django 1.8以前,管理命令基于optparse模块,位置参数传递给*args,可选参数传递给**options。如今,管理命令使用argparse解析参数,默认全部的参数都传递给**options,除非你命名你的位置参数为args(兼容模式)。对于新的命令,鼓励你仅仅使用**options。

this

当你使用管理命令并但愿提供控制台输出时,你应该写到self.stdoutself.stderr,而不能直接打印到 stdoutstderr。经过使用这些代理方法,测试你自定义的命令将变得很是容易。还请注意,你不须要在消息的末尾加上一个换行符,它将被自动添加,除非你指定ending参数:

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

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

handle()接收一个或多个poll_ids并为他们中的每一个设置 poll.openedFalse。若是用户访问任何不存在的polls,将引起一个CommandErrorpoll.opened属性在教程中并不存在,只是为了这个例子将它添加到polls.models.Poll中。

接收可选参数

经过接收额外的命令行选项,能够简单地修改closepoll来删除一个给定的poll而不是关闭它。这些自定义的选项能够像下面这样添加到 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',
            default=False,
            help='Delete poll instead of closing it')

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

以前,只支持标准的optparse库,你必须利用optparse.make_option()扩展命令option_list变量。

选项(在咱们的例子中为delete)在handle方法的options字典参数中能够访问到。更多关于add_argument用法的信息,请参考argparse的Python 文档。

除了能够添加自定义的命令行选项, 管理命令还能够接收一些默认的选项,例如--verbosity--traceback

管理命令和区域设置

默认状况下,BaseCommand.execute()方法使转换失效,由于某些与Django一块儿的命令完成的任务要求一个与项目无关的语言字符串(例如,面向用户的内容渲染和数据库填入)。

Changed in Django 1.8:

在以前的版本中,Django强制使用"en-us"区域设置而不是使转换失效。

若是,出于某些缘由,你的自定义的管理命令须要使用一个固定的区域设置,你须要在你的handle()方法中利用I18N支持代码提供的函数手工地启用和停用它:

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

class Command(BaseCommand):
    ...
    can_import_settings = True

    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(this is a good example of the potential problems stemming from a dynamic runtime environment that Django commands avoid offhand by deactivating translations)。

  • Review the code of your command and the code it calls for behavioral differences when locales are changed and evaluate its impact on predictable behavior of your command.

测试

关于如何测试自定义管理命令的信息能够在测试文档中找到。

Command 对象

class BaseCommand

全部管理命令最终继承的基类。

若是你想得到解析命令行参数并在响应中如何调用代码的全部机制,可使用这个类;若是你不须要改变这个行为,请考虑使用它的子类。

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

属性

全部的属性均可以在你派生的类中设置,并在BaseCommand的子类中使用。

BaseCommand.args

一个字符串,列出命令接收的参数,适合用于帮助信息;例如,接收一个应用名称列表的命令能够设置它为‘<app_label app_label ...>’。

Deprecated since version 1.8:

如今,应该在add_arguments()方法中完成,经过调用parser.add_argument()方法。参见上面的closepoll例子。

BaseCommand.can_import_settings

一个布尔值,指示该命令是否须要导入Django的设置的能力;若是为Trueexecute()将在继续以前验证这是否可能。默认值为True

BaseCommand.help

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

BaseCommand.missing_args_message

New in Django 1.8.

若是你的命令定义了必需的位置参数,你能够自定义参数缺失时返回的错误信息。默认是由argparse输出的 (“too few arguments”)。

BaseCommand.option_list

这是optparse选项列表,将赋值给命令的OptionParser用于解析命令。

Deprecated since version 1.8:

如今,你应该覆盖`add_arguments()`方法来添加命令行接收的自定义参数。参见上面的例子。

BaseCommand.output_transaction

一个布尔值,指示命令是否输出SQL语句;若是为True,输出将被自动用BEGIN;COMMIT;封装。默认为False

BaseCommand.requires_system_checks

New in Django 1.7.

一个布尔值;若是为True,在执行该命令以前将检查整个Django项目是否有潜在的问题。若是requires_system_checks缺失,则使用requires_model_validation的值。若是后者的值也缺失,则使用默认值(True)。同时定义requires_system_checksrequires_model_validation将致使错误。

BaseCommand.requires_model_validation

Deprecated since version 1.7:

被requires_system_checks代替

一个布尔值;若是为True,将在执行命令以前做安装的模型的验证。默认为True。若要验证一个单独应用的模型而不是所有应用的模型,能够调用在handle()中调用validate()

BaseCommand.leave_locale_alone

一个布尔值,指示设置中的区域设置在执行命令过程当中是否应该保持而不是强制设成‘en-us’。

默认值为False

若是你决定在你自定义的命令中修改该选项的值,请确保你知道你正在作什么。 若是它建立对区域设置敏感的数据库内容,这种内容不该该包含任何转换(好比django.contrib.auth权限发生的状况),由于将区域设置变成与实际上默认的‘en-us’ 不一样可能致使意外的效果。更进一步的细节参见上面的管理命令和区域设置一节。

can_import_settings选项设置为False时,该选项不能够也为False,由于尝试设置区域设置须要访问settings。这种状况将产生一个CommandError

方法

BaseCommand有几个方法能够被覆盖,可是只有handle()是必须实现的。

在子类中实现构造函数

若是你在BaseCommand的子类中实现__init__,你必须调用BaseCommand__init__

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super(Command, self).__init__(*args, **kwargs)
        # ...

BaseCommand.add_arguments(parser)

New in Django 1.8.

添加解析器参数的入口,以处理传递给命令的命令行参数。自定义的命令应该覆盖这个方法以添加命令行接收的位置参数和可选参数。当直接继承BaseCommand时不须要调用super()

BaseCommand.get_version()

返回Django的版本,对于全部内建的Django命令应该都是正确的。用户提供的命令能够覆盖这个方法以返回它们本身的版本。

BaseCommand.execute(*args, **options)

执行这个命令,若是须要则做系统检查(经过 requires_system_checks属性控制)。若是该命令引起一个CommandError,它将被截断并打印到标准错误输出。

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

不该该在你的代码中直接调用execute()来执行一个命令。请使用call_command

BaseCommand.handle(*args, **options)

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

BaseCommand.check(app_configs=None, tags=None, display_num_errors=False)

New in Django 1.7.

利用系统的检测框架检测所有Django项目的潜在问题。严重的问题将引起CommandError;警告会输出到标准错误输出;次要的通知会输出到标准输出。

若是app_configstags都为None,将进行全部的系统检查。tags能够是一个要检查的标签列表,好比compatibilitymodels

BaseCommand.validate(app=None, display_num_errors=False)

Deprecated since version 1.7:

被check命令代替

若是appNone,那么将检查安装的全部应用的错误。

BaseCommand 的子类

class AppCommand

这个管理命令接收一个或多个安装的应用标签做为参数,并对它们每个都作一些动做。

子类不用实现handle(),但必须实现handle_app_config(),它将会为每一个应用调用一次。

AppCommand.handle_app_config(app_config, **options)

app_config完成命令行的动做,其中app_configAppConfig的实例,对应于在命令行上给出的应用标签。

Changed in Django 1.7:

之前,AppCommand子类必须实现handle_app(app, **options),其中app是一个模型模块。新的API能够不须要模型模块来处理应用。迁移的最快的方法以下:

def handle_app_config(app_config, **options):
    if app_config.models_module is None:
        return                                  # Or raise an exception.
    app = app_config.models_module
    # Copy the implementation of handle_app(app_config, **options) here.

然而,你能够经过直接使用app_config的属性来简化实现。

class LabelCommand

这个管理命令接收命令行上的一个或多个参数(标签),并对它们每个都作一些动做。

子类不用实现handle(),但必须实现handle_label(),它将会为每一个标签调用一次。

LabelCommand.handle_label(label, **options)

label完成命令行的动做,label是命令行给出的字符串。

class NoArgsCommand

Deprecated since version 1.8:

使用BaseCommand代替,它默认也不须要参数。

这个命令不接收命令行上的参数。

子类不须要实现handle(),但必须实现handle_noargs()handle()自己已经被覆盖以保证不会有参数传递给命令。

NoArgsCommand.handle_noargs(**options)

完成这个命令的动做

Command 的异常

class CommandError

异常类,表示执行一个管理命令时出现问题。

若是这个异常是在执行一个来自命令行控制台的管理命令时引起,它将被捕获并转换成一个友好的错误信息到合适的输出流(例如,标准错误输出);所以,引起这个异常(并带有一个合理的错误描述)是首选的方式来指示在执行一个命令时某些东西出现错误。

若是管理命令从代码中经过call_command调用,那么须要时捕获这个异常由你决定。

译者:Django 文档协做翻译小组,原文:Adding custom commands

本文以 CC BY-NC-SA 3.0 协议发布,转载请保留做者署名和文章出处。

Django 文档协做翻译小组人手紧缺,有兴趣的朋友能够加入咱们,彻底公益性质。交流群:467338606。

相关文章
相关标签/搜索