Spec-Zone.ru › Django 1.10

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

В Python 2 убедитесь, что включены файлы __init__.py как в директориях management и management/commands, иначе ваша команда не будет обнаружена.

В этом примере команда closepoll будет доступна для любого проекта, который включает приложение polls в INSTALLED_APPS.

Модуль _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 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',
            default=False,
            help='Delete poll instead of closing it',
        )

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

Параметр (delete в нашем примере) доступен в словаре параметров options метода handle. Подробнее об использовании add_argument см. в документации Python argparse.

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

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

По умолчанию метод BaseCommand.execute() отключает переводы, поскольку некоторые команды, поставляемые с Django, выполняют несколько задач (например, вывод пользовательского контента и заполнение базы данных), которые требуют языка строк, нейтрального для проекта.

Если по какой-либо причине вашей пользовательской команде управления необходимо использовать фиксированную локаль, вы должны вручную активировать и деактивировать её в методе 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 при выполнении команды (это хороший пример потенциальных проблем, возникающих в динамической среде выполнения, которых Django-команды избегают, отключая переводы).
  • Пересмотреть код вашей команды и вызываемых ею функций на предмет поведенческих различий при изменении локалей и оценить его влияние на предсказуемое поведение вашей команды.

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

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

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

class BaseCommand [source]

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

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

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

Атрибуты

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

BaseCommand.can_import_settings

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

BaseCommand.help

Краткое описание команды, которое будет выведено в сообщении справки, когда пользователь выполнит команду python manage.py help <command>.

BaseCommand.missing_args_message

Если ваша команда определяет обязательные позиционные аргументы, вы можете настроить сообщение об ошибке, возвращаемое в случае отсутствия аргументов. По умолчанию это значение выводится argparse (“слишком мало аргументов”).

BaseCommand.output_transaction

Булево значение, указывающее, выводит ли команда SQL-запросы; если True, вывод будет автоматически заключён в BEGIN; и COMMIT;. Значение по умолчанию False.

BaseCommand.requires_migrations_checks
Добавлено в Django 1.10.

Булево значение; если True, команда выведет предупреждение, если набор миграций на диске не соответствует миграциям в базе данных. Предупреждение не предотвращает выполнение команды. Значение по умолчанию False.

BaseCommand.requires_system_checks

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

BaseCommand.leave_locale_alone

Логическое значение, указывающее, следует ли сохранить локаль, установленную в настройках, во время выполнения команды вместо принудительной установки «en-us».

Значение по умолчанию — False.

Убедитесь, что вы понимаете, что делаете, если решите изменить значение этого параметра в вашей пользовательской команде, если она создаёт данные базы данных, чувствительные к локали, и такие данные не должны содержать каких-либо переводов (как это происходит, например, с django.contrib.auth разрешениями), так как изменение локали с фактического значения по умолчанию «en-us» может привести к непредвиденным последствиям. Более подробные сведения см. в разделе «Команды управления и локали» выше.

Этот параметр не может быть False, когда параметр can_import_settings также установлен на False, поскольку для установки локали требуется доступ к настройкам. Это условие сгенерирует CommandError.

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(Command, self).__init__(*args, **kwargs)
        # ...
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]

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

Он может возвращать строку Unicode, которая будет выводиться в 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/1.10/howto/custom-management-commands/

Spec-Zone.ru

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