Написание собственных 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 dict метода handle. См. argparseДокументацию Python для получения дополнительной информации об 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замененную команду.

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

класс 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

Логическое значение; if 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имеет несколько методов, которые можно переопределить, но handle()должен быть реализован только метод.

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

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

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ...
BaseCommand.create_parser( имя_программы , подкоманда , ** kwargs )

Возвращает CommandParserэкземпляр, который является ArgumentParserподклассом с некоторыми настройками для Django.

Вы можете настроить экземпляр с помощью переопределения этого метода и вызова super()с kwargsиз ArgumentParserпараметров.

BaseCommand.add_arguments( парсер )

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

BaseCommand.get_version()

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

BaseCommand.execute( * аргументы , ** параметры )

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

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

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

BaseCommand.handle( * аргументы , ** параметры )

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

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

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

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

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

BaseCommandподклассы

класс AppCommand

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

Вместо реализации handle()необходимо реализовать подклассы handle_app_config(), которые будут вызываться один раз для каждого приложения.

AppCommand.handle_app_config( app_config , ** параметры )

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

класс LabelCommand

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

Вместо реализации handle()необходимо реализовать подклассы handle_label(), которые будут вызываться один раз для каждой метки.

LabelCommand.label

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

LabelCommand.handle_label( метка , ** варианты )

Выполните действия команды для label, которая будет строкой, указанной в командной строке.

Исключения команд

исключениеCommandError ( код возврата = 1 )

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

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

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

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

returncodeАргумент был добавлен.

Copyright ©2021 All rights reserved