Проект может быть расширен собственными командами для 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
В Python 2 не забудьте добавить файлы __init__.py в каталоги management и management/commands, иначе ваша команда не будет найдена.
В этом примере команда 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 Poll
class Command(BaseCommand):
help = 'Closes the specified poll for voting'
def add_arguments(self, parser):
parser.add_argument('poll_id', nargs='+', type=int)
def handle(self, *args, **options):
for poll_id in options['poll_id']:
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('Successfully closed poll "%s"' % poll_id)
До Django 1.8, команды управления использовали модуль optparse и позиционные аргументы передавались в *args, а необязательные аргументы - в **options. Теперь управляющие команды используют argparse для обработки аргументов, все аргументы по умолчанию передаются в``**options``, если вы явно не привязали позиционные аргументы к args (режим совместимости). Рекомендуется использование **options для новых команд.
Примечание
При реализации команды вы должны использовать 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_id', nargs='+', type=int)
# Named (optional) arguments
parser.add_argument('--delete',
action='store_true',
dest='delete',
default=False,
help='Delete poll instead of closing it')
def handle(self, *args, **options):
# ...
if options['delete']:
poll.delete()
# ...
РИанее, поддерживалась только стандартная библиотека optparse и вам требовалось расширять переменную option_list с помощью optparse.make_option().
Параметр (delete в нашем случае) доступен в словаре параметров метода handle(). Подробнее можно посмотреть в документации по argparse, где говорится про использование add_argument.
Помимо возможности принимать пользовательские опции, все стандартные команды принимают также опции по умолчанию, такие как --verbosity и --traceback.
По умолчанию BaseCommand.execute() отключает переводы, потому что встроенные команды, которые выполняют различные задачи (например, наполнение базы данных, генерация контента), требуют нейтральной кодировки.
В предыдущих версиях, Django переключалас на локаль “en-us” вместо отключения системы переводов.
Если пользовательская команда требует другой локали, то вы можете вручную активировать и деактивировать её в вашем handle(), используя функции по работе с интернационализацией (I18N):
from django.core.management.base import BaseCommand, CommandError
from django.utils import translation
class Command(BaseCommand):
...
can_import_settings = True
def handle(self, *args, **options):
# Activate a fixed locale, e.g. Russian
translation.activate('ru')
# Or you can activate the LANGUAGE_CODE # chosen in the settings:
from django.conf import settings
translation.activate(settings.LANGUAGE_CODE)
# Your command logic here
...
translation.deactivate()
Бывает, что команда должна просто использовать локаль, указанную в настройках проекта, и Django не должна отключать её. Это можно сделать, установив параметр BaseCommand.leave_locale_alone.
При использовании нестандартной локали будьте осторожны:
Убедитесь, что параметр USE_I18N установлен в True, когда команда запускается (это очень хороший пример потенциальных ошибок при использовании динамического окружения, поэтому Django решает эту проблему отключением переводов).
Убедитесь в работоспособности команды при разных локалях.
Информация, о том как тестировать команды управления, может быть найдена в соответствующей документации.
Базовый класс для всех команд.
Используйте этот класс, если хотите добраться до всех механизмов, которые занимаются разбором аргументов командной строки и возвратом значения. Если вам не нужно вносить изменения в поведение, используйте один из его подклассов.
Наследование от BaseCommand подразумевает, что будет реализован метод handle().
Все перечисленные атрибуты могут использоваться в производных от BaseCommand классах.
Строка со списком аргументов, которые принимает команда. Может использоваться в справочных сообщениях, например, команда, которая принимает список имён приложений может установить значение ‘<app_label app_label ...>’.
Не рекомендуется, начиная с версии 1.8: Это должно выполняться в методе add_arguments() с помощью вызова метода parser.add_argument(). Посмотрите на пример с closepoll выше.
Булево значение, которое определяет нужно ли команде импортировать настройки Django. Если установлено в True, то метод execute() проверит возможность импорта. Значение по умолчанию - True.
Краткое описание команды, которое будет выведено в справочном сообщении при выполнении python manage.py help <command>.
Если ваша команда определяет обязательные позиционные аргументы, вы можете настроить возвращаемое сообщение об ошибке, возвращаемое в случае пропуска аргументов. По умолчанию, возвращается ответ от argparse (“too few arguments”).
Список опций optparse, которые будут обрабатываться в OptionParser для получения аргументов.
Не рекомендуется, начиная с версии 1.8: Теперь надо переопределить метод add_arguments() для добавления дополнительных аргументов, принимаемых вашей командой. Смотрите пример выше.
Булево значение, которое определяет будет ли команда выводить SQL выражения. Если установлено в True, то весь вывод будет автоматически заключён между BEGIN; и COMMIT;. Значение по умолчанию - False.
Булево. При True, перед запуском команды Django выполнит проверку проекта на предмет ошибок. Если requires_system_checks не указан, используется значение requires_model_validation. Если этот атрибут так же не указан, используется значение по умолчанию (True). При указании requires_system_checks и requires_model_validation будет вызвана ошибка.
Не рекомендуется, начиная с версии 1.7: Заменен на requires_system_checks
Булево значение; если установлено в True, то проверка установленных моделей будет выполнена до выполнения команды. Значение по умолчанию True. Для валидации определённой модели приложения вместо всех вызывайте validate() из BaseCommand.handle().
Булево значение; указывает использовать ли локаль с настроек проекта, или ‘en-us’.
По умолчанию False.
Вы должны быть уверены в своих действиях при изменении этого параметра, если ваша команда меняет данные в базе данных, которые зависят от локали и не содержать переведенный текст (например, как это происходит в django.contrib.auth permissions), изменение локали на отличную от стандартной “en-us” может вызвать неожиданные эффекты. Смотрите выше раздел Команды и локализация для получения подробностей.
Этот параметр не может быть False, если can_import_settings равна False т.к. для установки локаль необходим доступ к настройкам. В таком случае будет вызвано исключение CommandError.
BaseCommand содержит несколько методов, которые могут быть переопределены, однако для минимальной работы команды требуется только реализация метода handle().
Переопределение конструктора
Если вы переопределяете __init__, убедитесь, что вызываете в нём __init__ базового класса BaseCommand:
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
super(Command, self).__init__(*args, **kwargs)
# ...
Точка входа для добавления аргументов парсера для обработки аргументов командной строки. Команды должны переопределять этот метод для добавления как позиционных, так и необязательных аргументов, принимаемых командой. Вызов super() не требуется при прямом наследовании BaseCommand.
Возвращает версию Django, которая необходима для работы всех встроенных команд Django. Пользовательские команды могут переопределить этот метод и вернуть свою версию.
Попытается выполнить команду, выполнив при необходимости проверку системы (регулируется атрибутом requires_system_checks). Если команда выбрасывает исключение CommandError, будет разумно перехватить его и распечатать в stderr.
Вызов команды в коде
Не вызывайте execute() непосредственно из кода команды. Используйте вместо этого call_command.
Собственно, логика команды. Ваш подкласс обязательно должен реализовывать этот метод.
Выполняет проверку проекта на предмет ошибок. Ошибки вызывают исключение CommandError, предупреждения просто выводятся в stderr, все остальные уведомления – в stdout.
Если app_configs и tags равны None, выполняется полная проверка. tags может содержкать список тегов, указывающих что проверять, например, compatibility или models.
Служебная команда, которая принимает в качестве аргументов имена установленных приложений и выполняет с ними однотипные действия.
Вместо реализации handle(), реализуйте метод handle_app_config(), который будет вызываться для каждого приложения.
Выполняет действия для app_config, который является объектом AppConfig приложения, которое было указано при выполнении команды.
В предыдущих версиях команда, унаследованная от:class:AppCommand, должна была реализовать метод handle_app(app, **options), где app был модуль с моделями. Новый API позволяет работать с приложениями без моделей. Самый простой способ обновить команды:
def handle_app_config(app_config, **options):
if app_config.models_module is None:
return # Or raise an exception.
app = app_config.models_module
# Copy the implementation of handle_app(app_config, **options) here.
Однако, лучше использовать атрибуты объекта app_config.
Команда, которая принимает один или несколько аргументов в командной строке (меток) и что-то делает с ними.
Вместо реализации handle() нужно реализовать handle_label(), который будет вызываться для каждого аргумента.
Выполняет действие для label, которая была передана через командную строку.
Не рекомендуется, начиная с версии 1.8: Используйте BaseCommand, который по умолчанию не требует аргументов.
Команда, которая не принимает аргументов.
Вместо реализации handle(), реализуйте handle_noargs(); в методе handle() можно проверить, что в команду не передаются аргументы.
Просто напишите код здесь.
Этот класс сигнализирует о неожиданных ситуациях при выполнении команды.
Если это исключение произошло в ходе выполнения команды из консоли, то оно будет преобразовано в понятное сообщение об ошибке и выведено в стандартный поток ошибок (например, stderr). Генерация этого исключения (с подробным описанием ошибки) - предпочтительный способ сообщения об исключительной ситуации в ходе выполнения команды.
Если команда будет вызвана из кода через call_command, то у вас будет шанс перехватить исключения.
Jun 02, 2016