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

简介: 编写自定义的django-admin命令应用可以通过manage.py注册它们自己的动作。例如,你可能想为你正在发布的Django应用添加一个manage.py动作。

编写自定义的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

在Python 2上,请确保managementmanagement/commands两个目录都包含__init__.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 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。

当你使用管理命令并希望提供控制台输出时,你应该写到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。

相关文章
|
20天前
|
数据库 Python
django中数据库外键可以自定义名称吗
django中数据库外键可以自定义名称吗
|
2月前
|
安全 数据库 数据安全/隐私保护
|
2月前
|
Shell Linux 数据库
Django管理命令大揭秘:如何打造定制脚本,实现任务自动化?
【8月更文挑战第31天】在现代Web开发中,自动化是提升效率和减少错误的关键。Django管理命令作为一种强大功能,允许我们在项目中轻松创建自定义脚本和自动化任务,如数据备份、报告生成等。通过在`app/commands`目录下创建`.py`文件,可以定义各种管理命令。例如,`send_daily_emails.py`用于发送日常邮件。我们定义一个继承自`BaseCommand`的类,并在`handle`方法中实现具体逻辑。管理命令不仅支持接收命令行参数,还可以充分利用Django的模型、视图和表单,帮助我们高效完成复杂任务。
23 0
|
2月前
|
前端开发 JavaScript 安全
Django入门到放弃之常见配置及基本命令
Django入门到放弃之常见配置及基本命令
|
2月前
|
SQL Shell API
python Django教程 之 模型(数据库)、自定义Field、数据表更改、QuerySet API
python Django教程 之 模型(数据库)、自定义Field、数据表更改、QuerySet API
|
2月前
|
Linux Shell 数据库
python Django教程 之 安装、基本命令、视图与网站
python Django教程 之 安装、基本命令、视图与网站
|
2月前
|
中间件 API 网络架构
Django后端架构开发:从匿名用户API节流到REST自定义认证
Django后端架构开发:从匿名用户API节流到REST自定义认证
22 0
|
4月前
|
关系型数据库 MySQL 开发工具
Django项目部署(命令函部署)
Django项目部署(命令函部署)
|
4月前
|
数据安全/隐私保护 Python
必知的技术知识:django自定义分页器
必知的技术知识:django自定义分页器
|
5月前
|
运维 监控 Serverless
Serverless 应用引擎产品使用之阿里函数计算中在自定义环境下用debian10运行django,用官方层的python3.9,配置好环境变量后发现自定义层的django找不到了如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。