Spec-Zone.ru › Django 2.1

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

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

Для этого просто добавьте директорию management/commands в приложение. Django будет регистрировать команду manage.py для каждого Python-модуля в этой директории, имя которого не начинается с нижнего подчеркивания. Например:

polls/
    __init__.py
    models.py
    management/
        commands/
            _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_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))

Примечание

При использовании команд управления и необходимости вывода в консоль, следует писать в self.stdout и self.stderr, а не выводить напрямую в stdout и stderr. Использование этих прокси делает гораздо проще тестирование вашей пользовательской команды. Обратите также внимание, что вам не нужно завершать сообщения символом новой строки, он будет добавлен автоматически, если вы не укажете параметр ending:

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

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

Метод 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_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 в нашем примере) доступен в словаре 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 2.1:

Декоратор @no_translations новый. В более старых версиях переводы отключались перед запуском команды, если атрибут команды leave_locale_alone (теперь удалённый) был установлен в True.

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

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

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

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

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

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

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

class BaseCommand [source]

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

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

Наследование от класса 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

Булево значение; если True, весь проект Django будет проверен на наличие возможных проблем до выполнения команды. Значение по умолчанию - True.

BaseCommand.style

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

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

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

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

Методы

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

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

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

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

Точка входа для добавления аргументов парсера для обработки аргументов командной строки, переданных команде. Пользовательские команды должны переопределять этот метод, чтобы добавить как позиционные, так и необязательные аргументы, принимаемые командой. Вызов super() не нужен при непосредственном наследовании от BaseCommand.

BaseCommand.get_version() [source]

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

BaseCommand.execute(*args, **options) [source]

Пытается выполнить эту команду, выполняя системные проверки, если это необходимо (как контролируется атрибутом requires_system_checks). Если команда вызывает исключение CommandError, оно перехватывается и выводится на stderr.

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

execute() не должен вызываться напрямую из вашего кода для выполнения команды. Используйте call_command() вместо этого.

BaseCommand.handle(*args, **options) [source]

Фактическая логика команды. Подклассы должны реализовать этот метод.

Он может вернуть строку, которая будет выведена на stdout (оборачивается BEGIN; и COMMIT; если output_transaction равно True).

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

Использует фреймворк системной проверки для проверки всего проекта 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 [source]

Класс исключений, указывающий на проблему во время выполнения команды управления.

Если это исключение возникает во время выполнения команды управления из консоли командной строки, оно будет перехвачено и преобразовано в хорошо отформатированное сообщение об ошибке в соответствующий поток вывода (то есть stderr); в результате, поднятие этого исключения (с осмысленным описанием ошибки) является предпочтительным способом указать, что что-то пошло не так при выполнении команды.

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

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

Spec-Zone.ru

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