Использование шаблонов Cheetah совместно с Django

    Однажды появилась необходимость выбрать шаблонизатор для использования с Django. На одном встроенном решении останавливаться я не хотел, а провел небольшое исследование производительности и удобства использования разных продуктов.

    На данный момент я выбрал Cheetah. Вот почему:


    Производительность


    В поисках хорошего шаблонизатора я наткнулся на статью «Multi engine template system», в которой приводилось сравнение скорости отрисовки шаблона различными движками.
    Тестирование проводилось на довольно простом шаблоне, который содержал:
    • строковую переменную ('hello world');
    • обход списка в 100 элементов;
    • вывод случайного числа;
    • обход модели Django с выводом аттрибутов.
    Cheetah всех уделал
    Явные лидеры теста — 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.
    Cheetah опять вдвое быстрее.

    Интересно было бы увидеть результаты тестирования 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) и занимает пару секунд. Кроме того, в ближайшее время я попробую автоматизировать эту операцию или найти готовое решение.


    Что почитать


    Важное дополнение про Jinja2


    Слово Jinja встречается в комментариях 11 раз, чаще всего в хорошем контексте. Конечно, я не мог игнорировать такие рекомендации и поставил этот шаблонизатор. Слова по этому поводу читайте в комментарии.

    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 19
    • +2
      Попробуйте ещё Jinja2. Похож на Django, ещё гибче, и работает очень быстро.
      • 0
        Пробежался по документации — не могу найти, поддерживается ли наследование шаблонов? Это очень важно.
        • 0
          Поддерживается, jinja.pocoo.org/2/documentation/templates#id5
          • 0
            Вижу, спасибо. Попробую как-нибудь…
            • НЛО прилетело и опубликовало эту надпись здесь
              • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  Отличная статья, спасибо! Пожалуй, нужно попробовать и jinja.

                  ...pain in the ass if you want to profile Django
                  Тут я согласен. Посмотрел графики и ужаснулся :-)

                  Я обращаю внимание на производительность потому, что разрабатываю проект, в котором скорость работы шаблонизатора будет очень критична. Для большинства задач хватит и стандартных шаблонов Django.

                  А насчет настроены/не настроены — за пару дней перепробовал 5 шаблонизаторов и XSLT. Ни с одним проблем не возникло. Подключаются в три строчки.
                  • +1
                    Продолжение — Jinja

                    C большим трудом настроил в итоге совместную работу Django и Jinja (оказалось, что в текущий релиз забыли включить директорию contrib со всеми файлами).

                    Работает очень быстро, выглядит вполне приятно. Особенно нравятся такие конструкции:
                    {% for type in types if type.parent_id == parent_id -%}
                        что-то там
                    {% endfor -%}
                    
                    Наследование поддерживается без всяких приключений с компиляцией.

                    Но не могу сделать две вещи: закешировать часть шаблона и присвоить переменной значение. Если я что-то не дочитал в документации и эти возможности в Jinja есть — подскажите, как они работают?
        • +1
          Говоря про автоматическую компиляцию — я, когда начинал писать препроцессор подмножества HAML в шаблоны Django(увы, так и не дописал), написал свой загрузчик шаблонов, являющийся оберткой для django.template.loaders.app_directories. Думаю, это самый простой метод.
          • +3
            У читы есть одна проблема — код выглядит как гавно.
            • 0
              А у кого лучше?
              • 0
                Django, Jinja.

                Сам я читах не пробовал, но в mako и pytenjin код тоже выглядит как говно :(
                • +1
                  Вот несколько примеров:
                  {# Django, Jinja #}
                  {% for item in item_list %}
                      <li>{{ item }}</li>
                  {% endfor %}
                  
                  
                  # PSP-style
                  <%= for item in item_list %>
                      <li><% item %></li>
                  <%= endfor %>
                  
                  
                  # Cheetah (mod)
                  ^for $item in $item_list
                      <li>$item</li>
                  ^end for
                  
                  
                  ## Mako
                  % for item in item_list:
                      <li>${item}</li>
                  % endfor
                  
                  
                  # Parser
                  ^for[item](0;10){
                      <li>$item</li>
                  }
                  
                  Мне кажется, все они одинаково ужасны. Спасти могут только правильная среда разработки и подсветка синтаксиса. Или XSLT.
                  • 0
                    А как в других нарисовать такое:
                    Html{% if condition %} condition text{% endif %}


                    Да, кстати, есть ещё Genshi, там типа тру xml. Но по мне Django-шаблоны гораздо лаконичнее.
                    • 0
                      Тру XML очень уж медленно работает. В восемь раз медленнее Cheetah.

                      В других:
                      {# Django, Jinja #}
                      Html{% if condition %} condition text{% endif %}
                      
                      
                      # PSP-style
                      Html<%= if condition %> condition text<%= endif %>
                      
                      
                      # Cheetah (mod)
                      Html^if $condition& condition text^end if&
                      
                      
                      ## Mako
                      Html
                      % if condition:
                      condition text
                      % endif
                      
                      
                      # Parser
                      Html^if(condition){ condition text}
                      
                      Опять же, всё дело в привычке и правильной подсветке. Из всех вариантов мне наиболее приятен Parser.
            • 0
              долгое время работал с Zope, поэтому, после небольшого освоения django нашел simpletemplate (мануал) — теперь и в django юзаю TAL, имхо, удобнее стандартного шаблона
              • 0
                обычно, удобство — всего лишь дело привычки.
              • 0
                Недавно наткнулся на Spitfire: code.google.com/p/spitfire/
                По описанию, урезанный Cheetah. И сильно быстрее.

                Вот тесты: stackoverflow.com/questions/1324238/what-is-the-fastest-template-system-for-python

                А тут отличия от Cheetah: code.google.com/p/spitfire/wiki/SpitfireVsCheetah

                Интересно твоё мнение в свете опыта с Cheetah.

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