Главная » Хабрахабр » [Из песочницы] Создание management commands в Django

[Из песочницы] Создание management commands в Django

Management commands — команды, выполняемые из командной строки с помощью скрипта manage.py.

Например, отправка пользователям разовых сообщений, получение выборки данных из БД, проверка наличия необходимых файлов и папок перед накатыванием обновлений, быстрое создание объектов модели при разработке и т.д.
Наиболее частые сферы применения — это действия, выполняемые разово или периодически, но для которых почему-либо недоступен запуск через планировщик.

Основы

Команды создаются в каталогах приложений (приложения должны быть добавлены в INSTALED_APPS), в подкаталоге app/management/commands. На каждую команду создается отдельный файл. Из командной строки будут доступны файлы, кроме тех, которые начинаются со знака подчеркивания.

app/ __init__.py management/ __init__.py commands/ __init__.py _tools.py zen.py

В данном примере команда zen будет доступна, а _tools — нет.

BaseCommand. Команды создаются наследованием от класса django.core.management.base. Эта команда будет выполнена, а возвращаемый ею результат напечатается в консоли. В простейшем случае достаточно переписать функцию handle.

from django.core.management.base import BaseCommand class Command(BaseCommand): help = 'The Zen of Python' def handle(self, *args, **options): import this

Попробуем вызвать нашу команду:

python manage.py zen
The Zen of Python, by Tim Peters Beautiful is better than ugly.
...

Аттрибут класса help — это описание, которое выводится при вызове команды с ключем --help или при неправильном вводе команды.

$ python manage.py zen --help
usage: manage.py zen [-h] [--version] [-v ] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] The Zen of Python optional arguments: -h, --help show this help message and exit --version show program's version number and exit -v {0,1,2,3}, --verbosity {0,1,2,3} Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output --settings SETTINGS The Python path to a settings module, e.g. "myproject.settings.main". If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will be used. --pythonpath PYTHONPATH A directory to add to the Python path, e.g. "/home/djangoprojects/myproject". --traceback Raise on CommandError exceptions --no-color Don't colorize the command output.

Парсинг аргументов

Как мы видим, наша команда уже принимает 7 аргументов.

Для этого необходимо создать в нашем классе функцию add_arguments, где перечислить все аргументы, которые мы хотим передавать нашей команде. А что, если нам этого мало и мы хотим добавить свои опции? Каждый аргумент создается путем вызова функции parser.add_argument с рядом параметров.

Предположим, нас не устраивает длинный вывод нашей функции и мы хотим, чтобы по ключам -s и --short печаталось просто Hello world:

from django.core.management.base import BaseCommand class Command(BaseCommand): help = 'The Zen of Python' def handle(self, *args, **options): if options['short']: import __hello__ else: import this def add_arguments(self, parser): parser.add_argument( '-s', '--short', action='store_true', default=False, help='Вывод короткого сообщения' )

Этот файл при вызове с ключем -s напечатает Hello world

$ python manage.py zen -s Hello world...
(coolwriter)$ python manage.py zen
The Zen of Python, by Tim Peters Beautiful is better than ugly.
Explicit is better than implicit.
...

Разберем подробнее, как задается парсинг аргументов.

ArgumentParser, и про аргументы, принимаемые функцией add_argument, можно почитать в документации к библиотеке argparse в документации python. Парсер наследуется от argparse. Самые важные следующие:

У нас это 'short', '-s' и '--short'.
action — что делать со значением аргумента. name or flags — имя или список имен и ярлыков. Наиболее интересные (но не все) варианты следующие:

Если передано несколько пар ключ-значенее, сохранится значение последней
store_const — сохранить в ключ name значение константы. store — сохранить как значение нашей опции. Константа передается в качестве аргумента const все той же функции add_argument.

Например:

parser.add_argument('my_option', action='store_const', const=1234)

Функции handle в options будет передано 'my_option': 1234

Сохраняется значение True либо False
append — значение будет аппендиться в конец списка
append_const — то же что предыдущее, но аппендится переданное в аргумент const значение (которое может быть любым объектом) store_true, store_false — частные случаи предыдущей опции.

Возможные значения: целое число, '?' — один либо дефолтное значение из аргумента default, '*' — все сколько есть, и собираются в список, '+' — хотя бы один, а если несколько — собираются в список, argparse. nargs — количество аргументов. Несовместима с action=const REMAINDER — туда собираются все оставшиеся аргументы из командной строки.

(При этом дефолтное значение передается как есть, без приведения к списку.) Обратите внимание: если вы используете этот аргумент, то значение вашей опции из командной строки будет передаваться в handle в виде списка, даже если там всего один элемент.

В значение choices передается список возможных значений
required — обязательный аргумент.
help — Описание того, что делает данный аргумент.
dest — если вы хотите сохранить вашу опцию под другим именем, можете указать dest='my_new_name'. default — значение по умолчанию.
type — приведение аргумента к указанному типу.
choices — ограничение вариантов значения аргумента. В противном случае будет использовано имя аргумента
Эти аргументы будут далее переданы функцию handle в виде словаря options.

А что, если мы хотим передать в handle неименованные аргументы?

Например, если мы хотим передать в команду несколько целых чисел: В этом случае нужно прописать в add_arguments получение всех неименованных аргументов в опцию args.

def add_arguments(self, parser):
parser.add_argument( nargs='+', type=int, dest = 'args' )

Порядок выполнения

Команда выполняется в следующем порядке:

  1. Вначале вызывается метод run_from_argv(). Этот метод создает парсер через вызов create_parser, а созданный парсер добавляет аргументы по умолчанию (типа no-color), а также вызывает метод add_arguments, добавляя таким образом все созданные нами опции.
  2. После этого вызывается функция execute. Эта функция выполняет несколько проверок, после чего запускает функцию handle. Результат выполнения handle печатается в стандартный поток вывода.

Конечно, любая из этих функций может быть кастомизирована. Например, давайте сделаем красивый вывод многострочного сообщения помощи:

from argparse import RawTextHelpFormatter def create_parser(self, prog_name, subcommand): parser = super(Command, self).create_parser(prog_name, subcommand) parser.formatter_class = RawTextHelpFormatter return parser

Вот, пожалуй, и все, что нужно для написания management commands в большинстве случаев.

Заключение

Статья не претендует на полноту обзора всех возможностей при создании management commands — они описаны в документации Django. Интересующиеся могут обратиться к
документации.

Желающим погрузиться в тонкости этого вопроса следует изучить докумантацию python. Парсинг аргументов командной строки там, увы, практически не раскрыт.

Модуль argparse


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Новые инструменты разработки с LEGO Education — от Microsoft, MIT и не только

Из шести кубиков LEGO размером 2х4 можно собрать 915 миллионов различных комбинаций. Но в LEGO Education конструирование из кубиков — это лишь часть дела. Даже проекты для дошкольников здесь включают в себя программирование, пусть и в простейшей форме. Мы стремимся ...

Используем 54 ФЗ на благо домашней бухгалтерии

Когда очередная редакция Федерального Закона номер 54 «О применении контрольно-кассовой техники» вступила в силу, большая часть населения встретила её негативно. Примерно вот так (18+, содержит нецензурную лексику) Я был одним из немногих, кто прыгал, хлопал в ладоши и вообще радовался ...