Как правильно отдавать команды

Про полезнейшую возможность делать свои команды для для 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")

Но как видно, эти два способа вынуждают повторно указывать значение по умолчанию, что не удобно и приводит к нежелательным ошибкам.

А вот если команда в чужом приложении, то вы обречены при таком использовании явно указывать все опции и даже те значения по умолчанию которых вас вполне устраивают. Не удобно.

Тикет и патч уже есть, так что возможно через некоторые время эта неприятная особенность вызова команд исчезнет. Подождем.