Про полезнейшую возможность делать свои команды для для manage.py я уже писал довольно-таки давно. Но поскольку пользуюсь ими регулярно, то с того времени уже сложились некоторые "правила хорошего тона" по написанию этих команд. Одно из них - внутри метода execute команды не стоит рассчитывать на то, что все опции, для которых вы даже прописали default значения, на самом дела присутствуют.
Покажу на примере. Типичная команда:
class Command(BaseCommand):
option_list = BaseCommand.option_list + [
make_option("-f", "--foo", default="bar", action="store")
]
def execute(self, *args, **options):
foo = options["foo"] # Вот тут и может случиться неожиданное!
# ...
Если запускать это команду через командную строку и без указания опции --foo, то всё будет хорошо - optparse любезно подставит значение по умолчанию и его можно будет спокойно использовать.
Но для вызова команд есть ещё один способ - внутри другого модуля с помощью функции call_command из django.core.management. И в этом случае аргументы и опции передают как параметры функции и при этом не учитываются значения по умолчанию, указанные в option_list. Т.е. если вы вызвали call_command("foobar") без опции foo, то код сломается с KeyError.
Если команду вы же и написали, то решения достаточно простые.
Можно, либо в execute прописывать параметры и значения по умолчанию в аргументах метода. Вот так:
def execute(self, foo="bar", *args):
# ...
Либо, не брать значение опции непосредственно по ключу из словаря, а "подстраховываться" через get:
def execute(self, *args, **options):
foo = options.get("foo", "bar")
Но как видно, эти два способа вынуждают повторно указывать значение по умолчанию, что не удобно и приводит к нежелательным ошибкам.
А вот если команда в чужом приложении, то вы обречены при таком использовании явно указывать все опции и даже те значения по умолчанию которых вас вполне устраивают. Не удобно.
Тикет и патч уже есть, так что возможно через некоторые время эта неприятная особенность вызова команд исчезнет. Подождем.
Оставьте комментарий