Spec-Zone.ru › Django 4.0

Как создать пользовательские команды django-admin

Приложения могут регистрировать собственные действия с помощью manage.py. Например, вы можете добавить действие manage.py для приложения Django, которое вы распространяете. В этом документе мы создадим пользовательскую команду closepoll для приложения polls из учебника.

Для этого добавьте директорию 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 или одного из его подклассов.

Самостоятельные скрипты

Пользовательские команды управления особенно полезны для запуска самостоятельных скриптов или для скриптов, которые периодически выполняются из crontab в Unix или из панели управления запланированными задачами в 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_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.stdout и self.stderr, вместо непосредственного вывода в stdout и stderr. Используя эти прокси, гораздо проще тестировать вашу пользовательскую команду. Обратите также внимание, что вам не нужно завершать сообщения символом новой строки, он будет добавлен автоматически, если вы не укажете параметр ending:

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

Новую пользовательскую команду можно вызвать с помощью python manage.py closepoll <poll_ids>.

Метод handle() принимает один или несколько poll_ids и устанавливает poll.opened в False для каждого из них. Если пользователь указал не существующие опросы, будет поднято исключение CommandError. Атрибут poll.opened не существует в учебнике и был добавлен в 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 в нашем примере) доступна в параметре options словаря метода handle. Смотрите документацию Python argparse для получения дополнительной информации об использовании add_argument.

В дополнение к возможности добавления пользовательских опций командной строки, все команды управления могут принимать некоторые стандартные опции, такие как --verbosity и --traceback.

Команды управления и языковые локали

По умолчанию команды управления выполняются с текущей активной локалью.

Если по какой-то причине ваша пользовательская команда управления должна выполняться без активной локали (например, чтобы предотвратить вставку переведенного контента в базу данных), отключите переводы, используя декоратор @no_translations на вашем методе handle():

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

class Command(BaseCommand):
    ...

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

Поскольку отключение переводов требует доступа к настроенным параметрам, декоратор не может быть использован для команд, работающих без настроенных параметров.

Тестирование

Информация о том, как протестировать пользовательские команды управления, находится в документации по тестированию.

Переопределение команд

Django регистрирует встроенные команды, а затем ищет команды в INSTALLED_APPS в обратном порядке. Во время поиска, если имя команды дублируется уже зарегистрированной командой, новая обнаруженная команда переопределяет первую.

Другими словами, чтобы переопределить команду, новая команда должна иметь то же имя, а её приложение должно располагаться перед приложением переопределяемой команды в INSTALLED_APPS.

Команды управления из сторонних приложений, которые были непреднамеренно переопределены, можно сделать доступными под новым именем, создав новую команду в одном из приложений вашего проекта (упорядоченном перед сторонним приложением в INSTALLED_APPS), которая импортирует Command переопределенной команды.

Объекты команд

class BaseCommand

Базовый класс, от которого в конечном итоге наследуются все команды управления.

Используйте этот класс, если вам нужен доступ ко всем механизмам, которые анализируют аргументы командной строки и определяют, какой код вызвать в ответ; если вам не нужно изменять это поведение, рассмотрите использование одного из его подклассов.

Наследование от класса BaseCommand требует реализации метода handle().

Атрибуты

Все атрибуты могут быть установлены в вашем производном классе и могут быть использованы в BaseCommand’s подклассах.

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]. Проверки системы зарегистрированные в выбранных тегах будут проверены на наличие ошибок перед выполнением команды. Значение '__all__' можно использовать для указания, что должны выполняться все проверки системы. Значение по умолчанию - '__all__'.

Изменено в Django 3.2:

В более старых версиях атрибут requires_system_checks ожидает булево значение вместо списка или кортежа тегов.

BaseCommand.style

Атрибут-экземпляр, который помогает создавать цветной вывод при записи в stdout или stderr. Например:

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

См. Цветной вывод синтаксиса, чтобы узнать, как изменить цветовую палитру и просмотреть доступные стили (используйте заглавные версии «ролей», описанных в этом разделе).

Если вы передаете опцию --no-color при выполнении вашей команды, все вызовы self.style() вернут исходную строку без цвета.

BaseCommand.suppressed_base_arguments
Новое в Django 4.0.

Опции команды по умолчанию, которые нужно подавить в выводе справки. Это должен быть набор имён опций (например, '--verbosity'). Значения по умолчанию для подавленных опций всё равно передаются.

Методы

BaseCommand имеет несколько методов, которые можно переопределить, но необходимо реализовать только метод handle().

Реализация конструктора в подклассе

Если вы реализуете __init__ в своем подклассе BaseCommand, вы должны вызвать __init__ метода BaseCommand:

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

Возвращает экземпляр 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_transaction имеет значение True).

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

Использует механизм проверки системы для проверки всего проекта Django на наличие потенциальных проблем. Серьезные проблемы поднимаются как исключение CommandError; предупреждения выводятся в stderr; незначительные уведомления выводятся в stdout.

Если app_configs и tags оба None, выполняются все проверки системы. tags может быть списком тегов проверок, например, compatibility или models.

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(), вам нужно перехватывать исключение при необходимости.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.0/howto/custom-management-commands/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API