12 сентября 2011 г.

Проверяем значение переменной на True, False, None в Django шаблонах

На собеседованиях часто приходиться спрашивать и слышать про шаблоны Django как узкое место фреймворка. И в большинстве случаев мы говорим про скорость выполнения, недостаточную гибкость и простоту при создании кастомных фильтров или тегов.

Но сегодняшний инцидент стоит просто за гранью моего понимания. Итак, есть модель с полем NullBooleanField, назовем его verified. Далее в шаблоне нужно отображать специфический класс для HTML-тега если verified is False. Что ж, это просто, за неимением is возпользуюсь проверенным ==:

<div{% if verified == False %} class="ui-state-error-text"{% endif %}>
    Some text
    Some input
</div>

Ок, обновляю страницу и думаю все ок. Однако, не тут-то было. Результата нет, в исходном тексте тоже никакого class="ui-state-error-text" нет и в помине. Странно. Ладно, дай думаю проверю в shell_plus. Проверка подтверждает мои опасения:

In [2]: t = Template('{% if verified == False %}False{% else %}Not False{% endif %}')

In [3]: t.render(Context({'verified': False}))
Out[3]: u'Not False'

In [4]: t.render(Context({'verified': True}))
Out[4]: u'Not False'

In [5]: t.render(Context({'verified': None}))
Out[5]: u'False'

Хм, ясное дело свитч на {% if not verified %} не достиг никаких результатов (теперь класс будет печататься и в случае, когда verified is None):

In [6]: t = Template('{% if not verified %}False{% else %}Not False{% endif %}')

In [7]: t.render(Context({'verified': False}))
Out[7]: u'False'

In [8]: t.render(Context({'verified': True}))
Out[8]: u'Not False'

In [9]: t.render(Context({'verified': None}))
Out[9]: u'False'

Хм, что же делать? Как же быть? Почему {% if verified == None %} работает если verified is None. Спросил совета у команды. И надо сказать их совет подействовал, надо просто проверку на False сменить на проверку на 0. И все начинает работать:

In [10]: t = Template('{% if verified == 0 %}False{% else %}Not False{% endif %}')

In [11]: t.render(Context({'verified': False}))
Out[11]: u'False'

In [12]: t.render(Context({'verified': True}))
Out[12]: u'Not False'

In [13]: t.render(Context({'verified': None}))
Out[13]: u'Not False'

Теперь вопрос, что заставило Django-девов не добавить boolean константы True и False в {% if %} темплейт тег? Где поддержка var is (None|True|False)? Уже ж сделали вроде как вменяемый if, что помешало сделать это раз и навсегда? Особенно в свете того, что поддержка конструкций item in list и item not in list была добавлена.

В целом был разочарован я изрядно, но теперь буду помнить, что для проверки на True, False в шаблонах надо сравнивать с 1 и 0. Прям как хрен знает где еще :(

blog comments powered by Disqus