Как стать автором
Обновить

Если поумнеет

Время на прочтение3 мин
Количество просмотров3.2K
Автор оригинала: Chris Beaven
Ох этот скромный {% if %}. Краеугольный камень шаблоной логики Django.

Каждый, кто начинал работать с Django 1.1 (или ранее), почти наверняка спотыкался об этот камень — шаблонный тег {% if %} поддерживает булеву логику только на базовом уровне.

Вообще, ограничение на работу тега только с переменной, которая имеет значение «true» (т.е. существует, не пустая и не ложь), было введено умышленно, чтобы подстрекать программистов разделять представление и логику.

Как-то раз я решил написать более гибкий и умный тег if. Посидев на выходных за клавиатурой, я опубликовал свой тег как сниппет, который очень скоро стал весьма популярным. А ещё восемь месяцев спустя была предложена замена тега if в Django 1.2.


Чего же нового, мистер If?


Начиная с Django 1.2 возможности {% if %} были расширены до поддержки базовой питонячей логики, позволяя вам делать такие вещи:

{% if you.friends.count > 5 %}Вы популярны!{% endif %}
{% if country != "NZ" %}Приезжайте к нам в Новую Зеландию.{% endif %}


При этом вы всё ещё можете использовать фильтры. Таким образом, вы можете без проблем писать {% if messages|length > 3 %}...{% endif %}.

Всё-таки не Python

Запомните: шаблоны Django — это всё-таки не Python. У вас нет доступа к ключевому слову None или встроенным python функциям. {% if movie == None %} не сработает так, как вы этого хотите. Но если вам не достаточно {% if not movie %}, вы определённо делаете что-то не так.

Сложная булева логика

Также тег теперь поддерживает одновременное использование and и or. Но я бы не советовал вам часто пользоваться этой возможностью, т.к. она частенько ведёт к путанице. Например:

{% if staff or author and not expired %}
<a href="{{ edit_url }}">Edit this</a>
{% endif %}


Дизайнерам может быть не понятно, что тут происходит («если пользователь принадлежит персоналу, но при этом время редактирования уже прошло, что будет?»). Было бы намного понятнее вычислить переменную can_edit во view и передать её в шаблон.

Если вам нужен порядок проверки условий, отличный от приоритета операций в Python, используйте несколько тегов if. Использование скобок не поддерживается.

Отсутствующие переменные

Важно помнить, что происходит, когда переменная не определена в контексте шаблона: её значение просто считается равным None.


Докопаемся до истины


Давайте посмотрим, что происходит там внутри (если вы не один из тех, кто любит ковыряться во внутренностях, можете пропустить эту часть).

В том самом сниппете парсер был совсем простой. Он работал, но не особо углубляясь в детали. Однако был в нём один значительный баг: операторы сравнения не имели превосходства над булевыми:

x or x == 0 парсилось как (x or x) == 0 вместо x or (x == 0).

Хоть это и удалось пофиксить, я никогда не был доволен получившимся кодом, что замечали и другие, например, Рассел Кейт-Мэги (Russel Keith-Magee). Позже Люк Плэнт (Luke Plant) поделился ссылкой на статью Фредрика Ланда (Fredrik Lundh) с описанием парсера под названием Simple Top-down Parsing in Python.

Также сниппет был в некоторой степени наивен при разборе сложных логических выражений. Например, «A or B and C» парсилось как "(A or B) and C", а не как в Python «A or (B and C)».

Улучшенная же реализация парсера и была отправлена в качестве патча. В итоге, парсер взвешивает операторы в том же порядке, что и Python (от низшего приоритета к высшему):
  • or
  • and
  • not
  • in
  • сравнения (==, !=, <, >, <=, >=)
Много свободного времени?

Прочитайте пару раз статью Simple Top-down Parsing in Python, попытайтесь понять, что там происходит, а потом… напишите свой собственный парсер.

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

Будучи мазохистом со стажем, я попытался сделать это, прочитав только первый параграф. Вот что у меня получилось.


Только потому что вы можете…


Не стоит бросаться и пихать во все шаблоны логику и сравнения. Разделяйте вашу бизнес логику и представление. Быть может, стоит сравнение перенести во view или даже в метод модели?..

О важности разделения логики и представления было сказано и написано уже много слов, но вот ещё пара причин.

Верстальщики — не программисты

Отсутствие логики в шаблонах позволит верстальщикам сосредоточиться на том, что они делают хорошо, а не на разбор таких вещей, как приоритет операторов сложной булевой логики.

Читаемость

Намного удобнее читать код бизнес логики без примесей шаблонного кода, точно так же, как и читать html код без мыслей о логике безопасности и структуре базы данных.


endif


Я могу бесконечно болтать о функционале и логике нового тега, так что давайте уже остановимся.

Хочется поблагодарить Luke Plant за его работу по подготовке всего этого дела к релизу в Django 1.2.

И, конечно же, не забудьте заглянуть в официальную документацию, где написано всё о возможностях нового тега if.
Теги:
Хабы:
Всего голосов 64: ↑50 и ↓14+36
Комментарии38

Публикации

Истории

Работа

Python разработчик
190 вакансий

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
26 октября
ProIT Network Fest
Санкт-Петербург
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань