Как создавать пользовательские команды django-admin
¶
Приложения могут регистрировать свои собственные действия с помощью manage.py
. Например, вы можете захотеть добавить действие manage.py
для приложения Django, которое вы распространяете. В этом документе мы будем создавать пользовательскую команду closepoll
для приложения polls
из tutorial.
Для этого необходимо добавить в приложение каталог 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
или один из его subclasses.
Автономные сценарии
Пользовательские команды управления особенно полезны для запуска автономных сценариев или для сценариев, которые периодически выполняются из кронтаба 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
не существует в tutorial и был добавлен в 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. Подробнее об использовании параметра <argparse
см. документацию по Python :py``add_argument``.
Помимо возможности добавления пользовательских параметров командной строки, все management commands могут принимать некоторые параметры по умолчанию, такие как --verbosity
и --traceback
.
Команды управления и локали¶
По умолчанию команды управления выполняются с текущей активной локалью.
Если по какой-то причине ваша пользовательская команда управления должна выполняться без активной локали (например, чтобы предотвратить вставку переведенного содержимого в базу данных), отключите переводы с помощью декоратора @no_translations
на вашем методе handle()
:
from django.core.management.base import BaseCommand, no_translations
class Command(BaseCommand):
...
@no_translations
def handle(self, *args, **options):
...
Поскольку деактивация перевода требует доступа к настроенным параметрам, декоратор нельзя использовать для команд, которые работают без настроенных параметров.
Тестирование¶
Информацию о том, как тестировать пользовательские команды управления, можно найти в разделе testing docs.
Переопределение команд¶
Django регистрирует встроенные команды, а затем ищет команды в INSTALLED_APPS
в обратном порядке. Во время поиска, если имя команды дублирует уже зарегистрированную команду, вновь найденная команда отменяет первую.
Другими словами, чтобы отменить команду, новая команда должна иметь такое же имя, а ее app должна находиться перед app отменяемой команды в INSTALLED_APPS
.
Команды управления из сторонних приложений, которые были непреднамеренно переопределены, могут быть доступны под новым именем путем создания новой команды в одном из приложений вашего проекта (расположенном перед сторонним приложением в INSTALLED_APPS
), которая импортирует Command
переопределенной команды.
Командные объекты¶
-
class
BaseCommand
[исходный код]¶
Базовый класс, от которого в конечном итоге происходят все команды управления.
Используйте этот класс, если вам нужен доступ ко всем механизмам, которые анализируют аргументы командной строки и определяют, какой код вызвать в ответ; если вам не нужно изменять ничего из этого поведения, подумайте об использовании одного из классов subclasses.
Подкласс класса BaseCommand
требует, чтобы вы реализовали метод handle()
.
Атрибуты¶
Все атрибуты могут быть установлены в вашем производном классе и могут быть использованы в BaseCommand
“subclasses“.
-
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]
. Системные проверки registered in the chosen tags перед выполнением команды будет произведена проверка на наличие ошибок. Значение'__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
из __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)[исходный код]¶ Использует фреймворк system check для проверки всего проекта 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()
, вы сами должны поймать исключение, когда это необходимо.