Как создать собственные команды 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 метода handle. Подробнее об использовании add_argument см. в документации Python по argparse.
Помимо возможности добавлять собственные параметры командной строки, все команды управления могут принимать некоторые параметры по умолчанию, например --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[исходный код]
Базовый класс, от которого в конечном итоге наследуются все команды управления.
Используйте этот класс, если вам нужен доступ ко всем механизмам разбора аргументов командной строки и определения вызываемого в ответ кода. Если вам не нужно менять это поведение, рассмотрите возможность использования одного из его подклассов.
При создании подкласса класса BaseCommand необходимо реализовать метод handle().
Атрибуты
Все атрибуты можно задать в производном классе и использовать в BaseCommand и его подклассах.
-
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().
Реализация конструктора в подклассе
Если в подклассе BaseCommand вы реализуете __init__, необходимо вызвать __init__ класса BaseCommand:
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ...
-
BaseCommand.create_parser(prog_name, subcommand, **kwargs)[исходный код] -
Возвращает экземпляр
CommandParser— подклассArgumentParserс несколькими настройками для Django.Можно настроить экземпляр, переопределив этот метод и вызвав
super()сkwargsпараметровArgumentParser.
-
BaseCommand.add_arguments(parser)[исходный код] -
Точка входа для добавления аргументов парсера, обрабатывающего аргументы командной строки, переданные команде. Пользовательским командам следует переопределить этот метод, чтобы добавить принимаемые командой позиционные и необязательные аргументы. При непосредственном наследовании от
BaseCommandвызыватьsuper()не требуется.
-
BaseCommand.get_version()[исходный код] -
Возвращает версию Django, которая должна быть правильной для всех встроенных команд Django. Команды, предоставленные пользователем, могут переопределить этот метод, чтобы возвращать собственную версию.
-
BaseCommand.execute(*args, **options)[исходный код] -
Пытается выполнить команду, при необходимости запуская системные проверки (управляется атрибутом
requires_system_checks). Если команда вызывает исключениеCommandError, оно перехватывается, а сообщение выводится вstderr.
Вызов команды управления из кода
Не следует напрямую вызывать execute() из своего кода для выполнения команды. Вместо этого используйте call_command().
-
BaseCommand.handle(*args, **options)[исходный код] -
Логика выполнения команды. Подклассы должны реализовать этот метод.
Метод может возвращать строку, которая будет выведена в
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)[исходный код] -
Использует систему проверок для поиска потенциальных проблем во всём проекте Django. Серьёзные проблемы приводят к исключению
CommandError; предупреждения выводятся вstderr; уведомления о незначительных проблемах — вstdout.Если
app_configsиtagsравныNone, выполняются все системные проверки, кроме проверок, связанных с развёртыванием и базой данных.tagsможет быть списком тегов проверок, напримерcompatibilityилиmodels.Можно передать
include_deployment_checks=True, чтобы также выполнить проверки развёртывания, а список псевдонимов баз данных указать вdatabases, чтобы запустить для них проверки, связанные с базами данных.
-
BaseCommand.get_check_kwargs(options)[исходный код] -
Добавлено в 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)[исходный код]
Класс исключения, указывающий на проблему при выполнении команды управления.
Если это исключение возникает при выполнении команды управления в консоли командной строки, оно перехватывается и преобразуется в понятное сообщение об ошибке, выводимое в соответствующий поток вывода (то есть stderr). Поэтому предпочтительнее всего вызывать это исключение (с понятным описанием ошибки), чтобы сообщить о проблеме при выполнении команды. Оно принимает необязательный аргумент returncode, позволяющий настроить код завершения команды управления, передаваемый в sys.exit().
Если команда управления вызывается из кода через call_command(), при необходимости перехватить исключение нужно самостоятельно.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/howto/custom-management-commands/