Django Framework

индекс
177,05

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

Ох этот скромный {% 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.
+36
18 марта 2010, 22:02
22

комментарии (38)

+2
Averrin #
Да, все это замечательно, но иногда так не хватает elif...=(
+1
damnerd #
Ну, если иногда, да ещё так не хватает, думаю, можно написать:

{% if condition %}
{% else %}
    {% if other_condition %}
    {% endif %}
{% endif %}
+7
Averrin #
Да обычно в коде выкручиваюсь. Жуть как не люблю вложеные условия. Но да, логичный вариант. Джаного рулит и педалит, не бросать же его из-за одного тега=)))
+2
VlK #
да ладно вам, как будто нет кастомных тегов if с endif в комлекте :)
–6
logan #
Обожаю джанго за вот такие красивые вещи.
+2
bolk #
Э… пардон. Мне тоже нравится Джанга, но про какую именно красивую вещь вы говорить в данном случае?
+8
S2nek #
Я перешел на тёмную сторону и использую jinja2. Из удобств не только умный if
0
letoosh #
Поддерживаю насчет Jinja2. На самом деле из всех аргументов разработчиков Джанги против нормальной логики в шаблонах, я вижу только один валидный и это упрощение разработки шаблонов для дизайнеров. Хотя, на мой взгляд, Jinja2 нисколько не сложнее в понимании чем движок самой Джанги.
+2
VlK #
а зачем вообще выносить в классическом и строгом mvc массивную логику в представление? Вот честно, зачем вам это?

вы бы хоть сказали, что производительность вы, кеширование аккуратней, прекомпиляция шаблонов и все такое, но логики не хватает… Это ж ерунда.
+1
Kigorw #
jinja2 великолепная вещь, жизнь упрощает капитально
+1
S2nek #
Только не нужно переусердствовать :-)
+3
klen #
Есть бизнес-логика, а есть логика представления. Как раз «недоразвитые» джанго-шаблоны и принуждают разработчиков, логику представления тянуть в обработчики поведения. В некоторых случаях даже заставляют смешивать код и разметку. И всяческие многочисленные костыли в виде темлейт-тегов только усугубляют положение.
0
damnerd #
И именно поэтому здорово, что джанго-шаблоны не стоят на месте, а развиваются. Да, таких возможностей тега if иногда не хватало для реализации именно шаблонной логики. Но теперь они появились. Но, как говорит автор статьи, не стоит переусердствовать, забыв о разделении бизнес логики и логики представления.
+2
lol2Fast4U #
А мне так нравилось
>ограничение на работу тега только с переменной, которая имеет значение «true» было введено умышленно, чтобы подстрекать программистов разделять представление и логику

теперь во всяких приложениях свитчеры с пхп будут всю логику в шаблонах писать :(
+2
lexazloy #
Дааа. Я-то думал, чем мне джанговские шаблоны не по душе. В них нет тега <?php.
–9
cleg #
а мне вот понадобилось из шаблона дернуть ф-ю и проитерироваться по ее результату.
и стало понятно что от шаблонов джанги надо уходить :(

потом что писать свой тег на этот случай — изврат
+3
alarin #
Может лучше сменить сферу деятельности? )))
НЛО прилетело и опубликовало эту надпись здесь
–2
cleg #
не надо кидаться огульными обвинениями…

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

идеальным был бы вариант: я передаю в шаблон функцию, которая возвращает заданное число записей, в шаблоне она дергается и по возвращенным ей результатам строится нужная таблица (список или что там надо дизайнеру). в любом другом шаблонном движке (от Cheetah до Jinja2) я бы так и сделал.
но не тут.

вопрос — и что тут такого плохого в том что я не размазываю абстракцию по слоям, а хочу собрать в одном месте?
НЛО прилетело и опубликовало эту надпись здесь
+1
neithere #
фильтр slice не подходит?
0
tenshi #
мдя… дурное влияние леммингов %-\
0
bobry #
к слову, есть пакет template_utils (http://code.google.com/p/django-template-utils/) который реализует >, >= etc
до релиза 1.2 — вполне себе можно потреблять
0
dmalinovsky #
Всё хорошо, но заголовок нужно перевести «if умнеет». Или «Оператор if умнеет». :))) А так получается что-то вроде машинного перевода.
+2
damnerd #
Вообще-то это специально так переведено, чтобы звучало более провокационно. ;)
0
dmalinovsky #
Цель явно достигнута. :)
–2
danSamara #
Собирался засесть за изучения Django, но после этой статьи как-то задумался.
Оператор if в любом языке — один из базовых. Если в шаблонах джанго он не доведён до ума (или находится в процессе), это говорит о достаточно сыром его состоянии.
+1
VlK #
вы очень ошибаетесь. Это сознательное решение, которое императивно подталкивает разработчиков не выносить логику в шаблоны.

Вы же не жалуетесь, что в Джаве не хватает множественного наследования, или что в интерпретаторах используется подсчет ссылок вместо явного выделения памяти!
0
danSamara #
На концептуальные решения я не жалуюсь. В конце концов не нравиться язык/фреймворк/библиотека/ещё-что-то — не используй.
Я про саму реализацию. Например про баг "x or x == 0 парсилось как (x or x) == 0 вместо x or (x == 0).". Если задекларирован разбор логики, то он должен работать. Если не работает — реализация сыра. Меня собственно это и удивляет — простой базовый оператор и не работает.
+1
eugenex15 #
а по моему вы бред несете!
задумывайтесь, и еще раз задумывайтесь, и ничего не учите!!!

PS django — это не только if в шаблоне.
0
danSamara #
Не горячитесь. Лучше объясните мне почему автор предлагает написать собственный парсер для if? Да, я понимаю, что для каждого проекта надо прописывать собственную логику, отдавая в шаблоны сформированные данные, но неужели надо переписывать ещё и стандартные тэги? Или это только IF так выделился?
+1
VlK #
Автор погорячился, не надо ничего переписывать, все уже давно написано за вас и нас. У меня где-то валялась специальная самосборная django app, сборная солянка изо всяких готовых расширений для тегов Джанго, там точно есть этот тег и другие сложные варианты стандартных тегов.

Но я перестал этим пользоваться, потому что в шаблонах не нужно, повторяю, не нужно, реализовывать никакой логики или, господа ради, каких-нибудь сложных switch/case.

Ну а про баг… Баг и баг, бывает. Уже поправили, кстати. В целом ядро django — крайне стабильная разработка, с прекрасной архитектурой, литературного качества кодом и супержесткими правилами принятия коммитов. Если точно, разработчиков там чуть ли не сотни, а права коммитов в репоз есть хорошо если у десятка человек.

В общем, если вам нравится Питон, то понравится и фремворк.

+1
danSamara #
Мне он уже нравиться. Но из-за не правильно понятой статьи испытал когнитивный диссонанс :)
Спасибо за комменты, теперь всё стало на свои места.
+2
kmike #
Вы, наверное, просто не так поняли то, что написано в статье.

Был сниппет с «умным» тегом if. Пример кода, который написал Chris Beaven. Сниппет стал популярным, его стали часто использовать. Решили включить аналогичный функционал в саму джангу. Перед включением сниппет привели в порядок и переписали. Описанный баг — это баг сниппета, а не того кода, который включен в джангу. В джанге все отлично работает, на тег if есть куча юнит-тестов, по этому поводу не переживайте.
+2
danSamara #
Спасибо за разъяснение, всё понятно.
Исчерпывающее количество комментариев :)
0
damnerd #
Эх, всё-таки Вы невнимательно читали и поторопились с выводами.

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

Автор считает, что если Вы заинтересовались, то, возможно, Вам также будет интересно и самому попробовать своими руками пощупать, что такое парсер.
0
damnerd #
Вот после таких комментариев возникает вопрос, плохо ли я перевёл, или Вы невнимательно читали.

Попробую объяснить, вдруг вина всё-таки моя: ошибки в парсинге были не в джанговом теге if, а в сниппете, который Крис накидал для себя за выходные. А когда это решили-таки добавить в Джанго, парсер допилили до ума.

Попробуйте перечитать топик с новыми силами, и не ночью, а после сна.
+1
danSamara #
Вы всё хорошо перевели. Просто я не «в теме», поэтому и задаю нубские вопросы.
В настоящий момент я разрабатываю сайты на Drupal. Отлично знаю систему, потратив на её изучение несколько лет. Решил, что пришло время освоить что-то новое. После поисков (rails, framework, etc.) остановился на django — отличный язык, отличный фреймворк.
И спасибо за статью :)

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