Создание пользовательских команд 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__'.Изменено в 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:
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) -
Использует систему проверки, чтобы проверить весь проект Django на наличие потенциальных проблем. Серьёзные проблемы поднимаются как
CommandError; предупреждения выводятся в stderr; незначительные уведомления выводятся в stdout.Если
app_configsиtagsоба имеют значениеNone, выполняются все системные проверки.tagsможет быть списком тегов проверки, например,compatibilityилиmodels.
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(), вы должны самостоятельно перехватывать исключение при необходимости.
Был добавлен аргумент returncode.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/howto/custom-management-commands/