Однажды появилась необходимость выбрать шаблонизатор для использования с Django. На одном встроенном решении останавливаться я не хотел, а провел небольшое исследование производительности и удобства использования разных продуктов.
На данный момент я выбрал Cheetah. Вот почему:
В поисках хорошего шаблонизатора я наткнулся на статью «Multi engine template system», в которой приводилось сравнение скорости отрисовки шаблона различными движками.
Тестирование проводилось на довольно простом шаблоне, который содержал:
Явные лидеры теста — Cheetah и Mako. По этому и другим тестам Cheetah более чем в 2 раза быстрее шаблонизатора Django. Mako в 1.7..2 раза быстрее Django.
Базовый шаблон содержал три блока: title, scripts, content. От него наследовался шаблон страницы, переопределяющий эти блоки. В title помещалась строка, в scripts – результат обхода списка из 100 строк, в content – результат обхода 100 объектов с выводом пяти их свойств. Страница, использующая шаблон, вызывалась 100 раз. Время первого вызова не учитывалось.
В результате среднее время генерации страницы было:
Интересно было бы увидеть результаты тестирования Mako со сложным шаблоном (с наследованием и выводом списка объектов).
Выбор между Mako и Cheetah я однозначно сделал из-за синтаксиса. Мне очень не нравится тегоподобный синтаксис большинства шаблонизаторов. Cheetah использует определенные символы для обозначения начала директивы и переменной. По умолчанию директивы начинаются с символа #, а переменные – с $. Это поведение можно переопределить используя директивы компилятора, что я и сделал:
У Cheetah и Python долгая совместная история (с 2001 года). На данный момент он поддерживается во всех серьезных веб-фреймворках на Python, в том числе в Django, TurboGears, Pylons...
Также его можно использовать и отдельно от каких-либо фреймворков.
Существует проект django-cheetahtemplate, который позволяет легко переключиться на использование шаблонов Cheetah. Подключив django_cheetahtemplates, вы получаете метод render_cheetah_response, который можно использовать вместо render_to_response. Еще можно подключить класс CheetahTemplate, который ведет себя аналогично классу Template из Django.
Django разбирает шалон на ноды сложным регулярным выражением. Применение шаблона сводится к выполнению метода render() для каждой ноды в переданном контексте. Cheetah собирает каждый шаблон в python-класс. Это занимает больше времени, но, видимо, дает преимущество в производительности при использовании этого шаблона. Есть мнение, что такой подход может быть небезопасным: шаблон может обратиться к каким-то данным, которые ему знать не положено. При неумелом использовании шаблонов может нарушаться логическое разделение документа и его представления.
Я считаю, что если нужна 100% универсальность и жесткое разделение данных и представления, то лучше использовать связку XML-XSLT. Правда, в этом случае для написания шаблона понадобится специально обученный человек, что не всегда удобно. И производительность у такого решения гораздо меньше.
Наследование возможно только от скомпилированного шаблона. Чаще всего, это не является проблемой, т. к. базовые шаблоны пишутся в первую очередь, а компиляция делается одной командой (
Слово Jinja встречается в комментариях 11 раз, чаще всего в хорошем контексте. Конечно, я не мог игнорировать такие рекомендации и поставил этот шаблонизатор. Слова по этому поводу читайте в комментарии.
На данный момент я выбрал Cheetah. Вот почему:
Производительность
В поисках хорошего шаблонизатора я наткнулся на статью «Multi engine template system», в которой приводилось сравнение скорости отрисовки шаблона различными движками.
Тестирование проводилось на довольно простом шаблоне, который содержал:
- строковую переменную ('hello world');
- обход списка в 100 элементов;
- вывод случайного числа;
- обход модели Django с выводом аттрибутов.
Явные лидеры теста — Cheetah и Mako. По этому и другим тестам Cheetah более чем в 2 раза быстрее шаблонизатора Django. Mako в 1.7..2 раза быстрее Django.
Для Cheetah я провел свое тестирование с более сложным шаблоном.
Базовый шаблон содержал три блока: title, scripts, content. От него наследовался шаблон страницы, переопределяющий эти блоки. В title помещалась строка, в scripts – результат обхода списка из 100 строк, в content – результат обхода 100 объектов с выводом пяти их свойств. Страница, использующая шаблон, вызывалась 100 раз. Время первого вызова не учитывалось.
В результате среднее время генерации страницы было:
- Django – 437 ms;
- Cheetah – 211 ms.
Интересно было бы увидеть результаты тестирования Mako со сложным шаблоном (с наследованием и выводом списка объектов).
Синтаксис
Выбор между Mako и Cheetah я однозначно сделал из-за синтаксиса. Мне очень не нравится тегоподобный синтаксис большинства шаблонизаторов. Cheetah использует определенные символы для обозначения начала директивы и переменной. По умолчанию директивы начинаются с символа #, а переменные – с $. Это поведение можно переопределить используя директивы компилятора, что я и сделал:
#compiler-settings directiveStartToken = ^ commentStartToken = # #end compiler-settings # выводим строку таблицы ^def makerow(row, class) <tr class=”${class}_ggg”> ^for $cell in $row: <td>$cell</td>^slurp ^end for </tr> ^end def
Универсальность
У Cheetah и Python долгая совместная история (с 2001 года). На данный момент он поддерживается во всех серьезных веб-фреймворках на Python, в том числе в Django, TurboGears, Pylons...
Также его можно использовать и отдельно от каких-либо фреймворков.
Как прикрутить?
Существует проект django-cheetahtemplate, который позволяет легко переключиться на использование шаблонов Cheetah. Подключив django_cheetahtemplates, вы получаете метод render_cheetah_response, который можно использовать вместо render_to_response. Еще можно подключить класс CheetahTemplate, который ведет себя аналогично классу Template из Django.
Какие-то проблемы?
Django разбирает шалон на ноды сложным регулярным выражением. Применение шаблона сводится к выполнению метода render() для каждой ноды в переданном контексте. Cheetah собирает каждый шаблон в python-класс. Это занимает больше времени, но, видимо, дает преимущество в производительности при использовании этого шаблона. Есть мнение, что такой подход может быть небезопасным: шаблон может обратиться к каким-то данным, которые ему знать не положено. При неумелом использовании шаблонов может нарушаться логическое разделение документа и его представления.
Я считаю, что если нужна 100% универсальность и жесткое разделение данных и представления, то лучше использовать связку XML-XSLT. Правда, в этом случае для написания шаблона понадобится специально обученный человек, что не всегда удобно. И производительность у такого решения гораздо меньше.
Наследование возможно только от скомпилированного шаблона. Чаще всего, это не является проблемой, т. к. базовые шаблоны пишутся в первую очередь, а компиляция делается одной командой (
cheetah compile template_name
) и занимает пару секунд. Кроме того, в ближайшее время я попробую автоматизировать эту операцию или найти готовое решение.Что почитать
- Cheetah прекрасно документирован на официальном сайте;
- А вот статья, где Django победил Cheetah.
Важное дополнение про Jinja2
Слово Jinja встречается в комментариях 11 раз, чаще всего в хорошем контексте. Конечно, я не мог игнорировать такие рекомендации и поставил этот шаблонизатор. Слова по этому поводу читайте в комментарии.