Написание 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_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 перегруженную команду.

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

класс BaseCommand

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

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

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

Атрибуты

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

BaseCommand.help

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

BaseCommand.missing_args_message

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

BaseCommand.output_transaction

Логическое значение, указывающее, отображает ли команда команды SQL; if 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 , вы должны вызвать метод __init__ из BaseCommand :

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ...
BaseCommand.create_parser( prog_name , подкоманда , ** kwargs )

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

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

BaseCommand.add_arguments( синтаксический анализ )

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

BaseCommand.get_version()

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

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

Пытается запустить эту команду, выполняя системные проверки по мере необходимости (в зависимости от значения атрибута requires_system_checks ). Если команда выдает ошибку 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 ); второстепенные уведомления отправляются на стандартный вывод ( stdout ).

Если 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 ©2020 All rights reserved