Spec-Zone.ru › Django 5.2

Как создавать пользовательские команды 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. См. документацию 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 [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

Список или кортеж тегов, например [Tags.staticfiles, Tags.models]. Проверки системы зарегистрированные в выбранных тегах будут проверены на наличие ошибок перед выполнением команды. Значение '__all__' может использоваться для указания того, что должны быть выполнены все проверки системы. Значение по умолчанию — '__all__'.

BaseCommand.style

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

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

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

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

BaseCommand.suppressed_base_arguments

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

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

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

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, include_deployment_checks=False, fail_level=checks.ERROR, databases=None) [source]

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

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

Вы можете передать include_deployment_checks=True для выполнения проверок развертывания, и список псевдонимов баз данных в databases для выполнения связанных с базой данных проверок.

BaseCommand.get_check_kwargs(options) [source]
Новое в Django 5.2.

Предоставляет аргументы ключевых слов для вызова check(), включая преобразование значения requires_system_checks в аргумент ключевого слова tag.

Переопределите этот метод, чтобы изменить значения, передаваемые в check(). Например, чтобы включить проверки, связанные с базой данных, вы можете переопределить get_check_kwargs() следующим образом:

def get_check_kwargs(self, options):
    kwargs = super().get_check_kwargs(options)
    return {**kwargs, "databases": [options["database"]]}

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) [source]

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

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

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

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

Spec-Zone.ru

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