Django 1.8 official document translation: 6-4-2 write a custom Django admin command

Time:2021-9-10

Write a custom Django admin command

Applications can bemanage.pyRegister their own actions. For example, you might want to add one for the Django application you are publishingmanage.pyAction. In the documentation on this page, we willpollsBuild a custom applicationclosepollCommand.

To do this, simply add one to the applicationmanagement/commandscatalogue Django will register one for each Python module in the directory whose name does not start with an underscoremanage.pyCommand. For example:

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

On Python 2, make suremanagementandmanagement/commandsBoth directories contain__init__.pyFile, otherwise your command will not be detected.

In this case,closepollCommands are available for any project as long as they areINSTALLED_APPSContainspollsApplication.

_private.pyWill not be available as an administrative command.

closepoll.pyA module has only one requirement – it must define oneCommandClass and extends fromBaseCommandOr its subclasses.

Stand alone script

Custom management commands are mainly used to run independent scripts or scripts periodically executed by UNIX crontab and windows periodic task control panel.

To implement this command, you need topolls/management/commands/closepoll.pyEdit as follows:

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:

Before Django 1.8, the management command was based on the optparse module, the location parameters were passed to * args, and the optional parameters were passed to * * options. Now, the management command uses argparse to parse parameters. By default, all parameters are passed to * * options, unless you name your location parameter args (compatibility mode). For new commands, you are encouraged to use only * * options.

notes

When you use administrative commands and want to provide console output, you should writeself.stdoutandself.stderrInstead of printing directly tostdoutandstderr。 By using these proxy methods, it will be very easy to test your custom commands. Also note that you do not need to add a line break at the end of the message, it will be added automatically unless you specifyendingParameters:

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

New custom commands can be usedpython manage.py closepoll <poll_id>Call.

handle()Receive one or morepoll_idsAnd set for each of thempoll.openedbyFalse。 If the user accesses any non-existentpolls, will raise aCommandErrorpoll.openedProperty does not exist in the tutorial, just add it to the for this examplepolls.models.PollYes.

Receive optional parameters

You can simply modify it by receiving additional command-line optionsclosepollTo delete a givenpollInstead of closing it. These custom options can be added to the followingadd_arguments()Method:

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:

Previously, only the standard optparse library was supported. You must use optparse.make_ Option() extension command_ List variable.

Option (in our exampledelete)InhandleMethodicaloptionsCan be accessed in dictionary parameters. More aboutadd_argumentFor usage information, refer toargparsePython documentation for.

In addition to adding custom command line options, management commands can also receive some default options, such as--verbosityand--traceback

Manage commands and locales

By default,BaseCommand.execute()Method invalidates the conversion because some commands with Django perform tasks that require a project independent language string (for example, user oriented content rendering and database filling).

Changed in Django 1.8:

In previous releases, Django forced the use of the "en US" locale instead of invalidating the conversion.

If, for some reason, your custom administrative commands need to use a fixed locale, you need to be in yourhandle()Method uses the functions provided by the I18N support code to manually enable and disable it:

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

Another need may be that your command should simply use the locale set in the settings, and Django should keep it disabled. You can useBaseCommand.leave_locale_aloneOption to implement this function.

Although the scenario described above can work, considering that the system management command must be very careful about running non-uniform locale settings, you may need to:

  • Ensure that when running the commandUSE_I18NSet to alwaysTrue(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.

test

Information on how to test custom administrative commands can be found inTest documentationFound in.

Command object

class BaseCommand

The base class that all management commands ultimately inherit.

If you want to get all the mechanisms for parsing command line parameters and how to call code in the response, you can use this class; If you don’t need to change this behavior, consider using its subclasses.

inheritBaseCommandClass requires you to implementhandle()method.

attribute

All properties can be set in your derived class, andBaseCommandUsed in subclasses of.

BaseCommand.args

A string that lists the parameters received by the command and is suitable for help information; For example, a command that receives an application name list can set it to‘<app_label app_label ...>’。

Deprecated since version 1.8:

Now, it should be in add_ Arguments () method by calling parser. Add_ Argument() method. See the closepoll example above.

BaseCommand.can_import_settings

A Boolean value indicating whether the command needs the ability to import Django settings; If yesTrueexecute()This will be verified before continuing. The default value isTrue

BaseCommand.help

A short description of the command when the user runspython manage.py help <command>Command will be printed in the help message.

BaseCommand.missing_args_message

New in Django 1.8.

If your command defines the required location parameters, you can customize the error message returned when the parameters are missing. The default is byargparseOutput (“too feed arguments”).

BaseCommand.option_list

This is a list of optparse options. The optionparser assigned to the command is used to parse the command.

Deprecated since version 1.8:

Now you should overwrite ` add_ Arguments() ` method to add custom parameters received from the command line. See the example above.

BaseCommand.output_transaction

A Boolean value indicating whether the command outputs SQL statements; If yesTrue, the output will be used automaticallyBEGIN;andCOMMIT;Encapsulation. Default toFalse

BaseCommand.requires_system_checks

New in Django 1.7.

A Boolean value; If yesTrue, the entire Django project will be checked for potential problems before executing this command. Ifrequires_system_checksMissing, userequires_model_validationValue of. If the latter value is also missing, the default value is used(True)。 Simultaneous definitionrequires_system_checksandrequires_model_validationWill cause an error.

BaseCommand.requires_model_validation

Deprecated since version 1.7:

Required_ system_ Checks instead

A Boolean value; If yesTrue, the installed model will be verified before executing the command. Default toTrue。 To validate a single applied model instead of all applied models, you can callhandle()Call invalidate()

BaseCommand.leave_locale_alone

A Boolean value indicating whether the locale in the setting should be maintained rather than forced to ‘en US’ during command execution.

The default value isFalse

If you decide to change the value of this option in your custom command, make sure you know what you are doing. If it creates locale sensitive database content, it should not contain any transformations (such asdjango.contrib.authPermission), because changing the locale to be different from the actual default ‘en US’ may lead to unexpected effects. See above for further detailsManage commands and localesA section.

Whencan_import_settingsOption set toFalseThis option cannot or cannot beFalse, because an attempt to set the locale requires accesssettings。 This situation will produce aCommandError

method

BaseCommandThere are several methods that can be overridden, but onlyhandle()It must be realized.

Implement constructors in subclasses

If you areBasecommandImplementation in subclasses__init__, you must callBaseCommandof__init__

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

BaseCommand.add_arguments(parser)

New in Django 1.8.

Add an entry to the parser parameters to handle the command line parameters passed to the command. Custom commands should override this method to add positional and optional parameters received by the command line. When direct inheritanceBaseCommandThere is no need to callsuper()

BaseCommand.get_version()

Return the Django version, which should be correct for all built-in Django commands. User supplied commands can override this method to return their own version.

BaseCommand.execute(*args, **options)

Execute this command and check the system if necessary (passrequires_system_checksAttribute control). If the command raises aCommandError, it will be truncated and printed to standard error output.

Invoke the administrative command in your code

Should not be called directly in your codeexecute()To execute a command. Please usecall_command

BaseCommand.handle(*args, **options)

The real logic of the command. Subclasses must implement this method.

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

New in Django 1.7.

The detection framework of the system is used to detect the potential problems of all Django projects. Serious problems will lead toCommandError; The warning will be output to the standard error output; Minor notifications are output to standard output.

Ifapp_configsandtagsAll forNone, all system checks will be performed.tagsIt can be a list of tags to check, such ascompatibilityormodels

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

Deprecated since version 1.7:

Replaced by check command

IfappbyNone, all installed applications will be checked for errors.

Subclass of basecommand

class AppCommand

This management command takes one or more installed application tags as parameters and takes some actions on each of them.

Subclasses do not need to be implementedhandle(), but it must be realizedhandle_app_config(), it will be called once for each application.

AppCommand.handle_app_config(app_config, **options)

yesapp_configComplete the action of the command line, whereapp_configyesAppConfigCorresponding to the application tag given on the command line.

Changed in Django 1.7:

Previously, the appcommand subclass had to implementhandle_app(app, **options), whereappIs a model module. The new API can handle applications without model modules. The fastest way to migrate is as follows:

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.

However, you can use it directlyapp_configTo simplify implementation.

class LabelCommand

This administrative command receives one or more parameters (labels) on the command line and takes some action on each of them.

Subclasses do not need to be implementedhandle(), but it must be realizedhandle_label(), it will be called once for each tag.

LabelCommand.handle_label(label, **options)

yeslabelComplete the action of the command line,labelIs the string given on the command line.

class NoArgsCommand

Deprecated since version 1.8:

Use basecommand instead, which does not require parameters by default.

This command does not accept parameters on the command line.

Subclasses do not need to be implementedhandle(), but it must be realizedhandle_noargs()handle()Itself has been overridden to ensure that no parameters are passed to the command.

NoArgsCommand.handle_noargs(**options)

Complete the action of this command

Command exception

class CommandError

Exception class, indicating that there is a problem when executing a management command.

If this exception is raised when executing an administrative command from the command line console, it will be captured and converted into a friendly error message to the appropriate output stream (for example, standard error output); Therefore, throwing this exception (with a reasonable error description) is the preferred way to indicate that something went wrong when executing a command.

If the management command calls from the code_ Command is called, so it’s up to you to catch this exception when necessary.

translator:Django document collaborative translation team, Original:Adding custom commands

In this paperCC BY-NC-SA 3.0Please keep the author’s signature and the source of the article.

Django document collaborative translation teamThere is a shortage of staff. Interested friends can join us. It is completely public welfare. Communication group: 467338606.