Ох этот скромный
Каждый, кто начинал работать с Django 1.1 (или ранее), почти наверняка спотыкался об этот камень — шаблонный тег
Вообще, ограничение на работу тега только с переменной, которая имеет значение «true» (т.е. существует, не пустая и не ложь), было введено умышленно, чтобы подстрекать программистов разделять представление и логику.
Как-то раз я решил написать более гибкий и умный тег if. Посидев на выходных за клавиатурой, я опубликовал свой тег как сниппет, который очень скоро стал весьма популярным. А ещё восемь месяцев спустя была предложена замена тега if в Django 1.2.
Начиная с Django 1.2 возможности
При этом вы всё ещё можете использовать фильтры. Таким образом, вы можете без проблем писать
Запомните: шаблоны Django — это всё-таки не Python. У вас нет доступа к ключевому слову
Также тег теперь поддерживает одновременное использование
Дизайнерам может быть не понятно, что тут происходит («если пользователь принадлежит персоналу, но при этом время редактирования уже прошло, что будет?»). Было бы намного понятнее вычислить переменную can_edit во view и передать её в шаблон.
Если вам нужен порядок проверки условий, отличный от приоритета операций в Python, используйте несколько тегов if. Использование скобок не поддерживается.
Важно помнить, что происходит, когда переменная не определена в контексте шаблона: её значение просто считается равным
Давайте посмотрим, что происходит там внутри (если вы не один из тех, кто любит ковыряться во внутренностях, можете пропустить эту часть).
В том самом сниппете парсер был совсем простой. Он работал, но не особо углубляясь в детали. Однако был в нём один значительный баг: операторы сравнения не имели превосходства над булевыми:
Хоть это и удалось пофиксить, я никогда не был доволен получившимся кодом, что замечали и другие, например, Рассел Кейт-Мэги (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 (от низшего приоритета к высшему):
Прочитайте пару раз статью Simple Top-down Parsing in Python, попытайтесь понять, что там происходит, а потом… напишите свой собственный парсер.
Если нужно, можете снова подглядеть в статью, но интерес в том, чтобы переписать функционал, поняв идею, а не просто стащить готовую реализацию.
Будучи мазохистом со стажем, я попытался сделать это, прочитав только первый параграф. Вот что у меня получилось.
Не стоит бросаться и пихать во все шаблоны логику и сравнения. Разделяйте вашу бизнес логику и представление. Быть может, стоит сравнение перенести во view или даже в метод модели?..
О важности разделения логики и представления было сказано и написано уже много слов, но вот ещё пара причин.
Отсутствие логики в шаблонах позволит верстальщикам сосредоточиться на том, что они делают хорошо, а не на разбор таких вещей, как приоритет операторов сложной булевой логики.
Намного удобнее читать код бизнес логики без примесей шаблонного кода, точно так же, как и читать html код без мыслей о логике безопасности и структуре базы данных.
Я могу бесконечно болтать о функционале и логике нового тега, так что давайте уже остановимся.
Хочется поблагодарить Luke Plant за его работу по подготовке всего этого дела к релизу в Django 1.2.
И, конечно же, не забудьте заглянуть в официальную документацию, где написано всё о возможностях нового тега if.
{% 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.