Как создать пользовательские команды 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. Обратитесь к документации 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
Базовый класс, от которого в конечном счёте происходят все команды управления.
Используйте этот класс, если вам нужен доступ ко всем механизмам, которые анализируют аргументы командной строки и определяют, какой код вызвать в ответ; если вам не нужно изменять это поведение, рассмотрите возможность использования одного из его подклассов.
Наследование от класса 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, вы должны вызвать метод BaseCommand’s __init__:
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) -
Точка входа для добавления аргументов парсера для обработки аргументов командной строки, переданных команде. Пользовательские команды должны переопределять этот метод для добавления позиционных и необязательных аргументов, принимаемых командой. Вызов
super()не требуется при непосредственном наследовании отBaseCommand.
-
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 подклассы
-
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/5.0/howto/custom-management-commands/