Реализация собственных команд django-admin¶
Проект может быть расширен собственными командами для manage.py. Например, вы можете добавить действие для развёртывания. Здесь же мы будем реализовывать действие closepoll для приложения polls из tutorial.
Для этого добавим в приложение каталог management/commands. Для каждого модуля в этом каталоге, который не начинается с подчёркивания, Django создаст соответствующую команду. Например:
polls/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
closepoll.py
tests.py
views.py
В этом примере команда closepoll будет доступна для любого проекта, который импортирует приложение polls в INSTALED_APPS.
Модуль _private.py не доступен как команда для manage.py.
Для модуля closepoll.py должно быть соблюдено лишь одно требование - наличие в нём класса Command, который унаследован от BaseCommand или его потомков.
Автономные скрипты
Собственные команды могут быть полезны для реализации отдельных скриптов, например, для планировщика Windows или crontab.
Для реализации команды отредактируйте 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_id>.
Метод handle() принимает один или более poll_ids и устанавливает каждому poll.opened в False. Если пользователь запросит несуществующий опрос, то будет выброшено исключение CommandError. Атрибут poll.opened не существует в tutorial и добавлен в polls.models.Poll в этом примере.
Получение необязательных аргументов¶
Аналогичный 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()
# ...
The option (delete in our example) is available in the options dict
parameter of the handle method. See the argparse Python documentation
for more about add_argument usage.
Помимо возможности принимать пользовательские опции, все стандартные команды принимают также опции по умолчанию, такие как :djadminopt:`--verbosity` и :djadminopt:`--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¶
If your command defines mandatory positional arguments, you can customize the message error returned in the case of missing arguments. The default is output by
argparse(«too few arguments»).
- 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("..."))
Смотрите Подсветка синтаксиса, чтобы узнать доступные стили и как поменять цвета (используйте названия «ролей», описанных в этом разделе, в верхнем регистре).
Если указать опцию :djadminopt:`--no-color` при запуске команды, все вызовы
self.style()вернут оригинальную строку без выделения цветом.
- BaseCommand.suppressed_base_arguments¶
Параметры команды по умолчанию для подавления в выводе справки. Это должен быть набор имен параметров (например,
'--verbosity'). Значения по умолчанию для подавляемых параметров по-прежнему передаются.
Методы¶
BaseCommand содержит несколько методов, которые могут быть переопределены, однако для минимальной работы команды требуется только реализация метода handle().
Переопределение конструктора
Если вы переопределяете __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)¶
Точка входа для добавления аргументов парсера для обработки аргументов командной строки. Команды должны переопределять этот метод для добавления как позиционных, так и необязательных аргументов, принимаемых командой. Вызов
super()не требуется при прямом наследованииBaseCommand.
- BaseCommand.get_version()¶
Возвращает версию Django, которая необходима для работы всех встроенных команд Django. Пользовательские команды могут переопределить этот метод и вернуть свою версию.
- BaseCommand.execute(*args, **options)¶
Попытается выполнить команду, выполнив при необходимости проверку системы (регулируется атрибутом
requires_system_checks). Если команда выбрасывает исключениеCommandError, будет разумно перехватить его и распечатать в stderr.
Вызов команды в коде
Не вызывайте execute() непосредственно из кода команды. Используйте вместо этого call_command.
- BaseCommand.handle(*args, **options)¶
Собственно, логика команды. Ваш подкласс обязательно должен реализовывать этот метод.
Может вернуть Unicode строку, которая будет выведена в
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)¶
Выполняет проверку проекта на предмет ошибок. Ошибки вызывают исключение
CommandError, предупреждения просто выводятся вstderr, все остальные уведомления – вstdout.Если
app_configsиtagsравныNone, выполняется полная проверка.tagsможет содержкать список тегов, указывающих что проверять, например,compatibilityилиmodels.Вы можете передать
include_deployment_checks=True, чтобы также выполнить проверки развертывания, и список псевдонимов баз данных вdatabases, чтобы запустить проверки, связанные с базой данных.
- BaseCommand.get_check_kwargs(options)¶
- New in Django 5.2.
Supplies kwargs for the call to
check(), including transforming the value ofrequires_system_checksto thetagkwarg.Override this method to change the values supplied to
check(). For example, to opt into database related checks you can overrideget_check_kwargs()as follows: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). Генерация этого исключения (с подробным описанием ошибки) - предпочтительный способ сообщения об исключительной ситуации в ходе выполнения команды.
Если команда будет вызвана из кода через call_command, то у вас будет шанс перехватить исключения.