Шаблоны Django. Наследование.

    Прочитал статью «Фрагментарное кэширование в MVC веб-фреймворках». Статья описывает проблему кеширования фрагмета отображения, а именно проблему полного разделения контроллера и отображения — контроллер отрабатывает полностью до вызова отображения. Если в отображении мы кешируем фрагмент, это ничего не меняет — контроллер-то уже отработал! В статье описан способ этого избежать: сделать запрос данных «ленивым».

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

    Как это сделано в Django?



    Структура шаблонов Django


    Управляющими элементами шаблонов Django являются переменные, фильтры и теги.

    При рендеринге шаблона переменные заменяются на свое значение, вычисленное в контексте вызова. Синтаксис — двойные фигурные скобки — например: {{ title }}.

    Фильтры служат для простых преобразований переменных. Синтаксис — переменная|имя_фильтра:"параметры". Фильтр может встречаться как в переменных, так и в качестве параметра тега. Например: {{ title|lowercase }}.

    При рендеринге шаблона теги, грубо говоря, заменяются на результаты работы ассоциированной с этим тегом функции на питоне. Синтаксис: {% тег параметры %}, например: {% url blog_article slug=article.slug %}.

    Программист может написать свои фильтры и теги, но об этом позже.

    Кроме того, есть три специальных тега: include, block и extend. Тег include подставляет запрошенный шаблон (отрендеренный в текущем контексте).

    Все выше перечисленное тривиально и в той или иной форме есть в любом движке шаблонов. Теперь перейдем к особенностям Django: на тегах block и extend строится наследование шаблонов. Остановимся на них подробнее.

    Наследование шаблонов


    Основная фишка шаблонов Django — наследование. Шаблон может расширять (уточнять) поведение родительского шаблона.

    Любой участок шаблона может быть обернут в блочный тег (естественно, что тег не может начинаться перед, а заканчиваться внутри цикла). Блоку дается имя. Например:
    {% block content %}
    	тело блока
    {% endblock %}
    


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

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

    Пример наследования шаблонов


    Допустим, мы хотим сделать сайт, содержащий простые страницы и блог.

    От верстальщика мы получили макет страницы, содержащий:

    • шапку (логотип, заголовок страницы, меню);
    • тело страницы;
    • и «подвал» с информацией о правах распространения.


    Вот как это выглядит:
    {% block head %}
    	{% block title %}{% endblock %}
    	{% block menu %}{% endblock %}
    {% endblock %}
    
    {% block page %}
    	{% block content %}
    	{% endblock %}
    {% endblock %}
    
    {% block footer %}
    	{% block copyright %}
    	{% endblock %}
    {% endblock %}
    



    Для всех указанных элементов мы создаем соответствующие блочные теги.

    Простая страница ложится в этот макет — у нее есть только заголовок и тело.

    Теперь перейдем к блогу. В блоге хотелось бы добавить правую колонку для вывода списка тегов и последних статей. Возможно мы захотим добавить правую колонку к каким-нибудь другим страницам сайта. Чтобы избежать копирования «двухколоночности», вынесем ее в отдельный шаблон, переопределив тело страницы у базового.
    {% extend "base.htm" %}
    
    {% block page %}
    	{% block content %}
    	{% endblock %}
    
    	{% block sidebar %}
    	{% endblock %}
    {% endblock %}
    



    В блоге будет несколько типов страниц:
    • список статей;
    • статья;
    • список тегов;
    • список статей, у которых есть определенный тег;
    • пр.


    У всех страниц правая колонка остается неизменной, поэтому разумно сделать базовую страницу для блога, наследуя ее от двухколоночной базовой страницы.
    {% extend "base_2col.htm" %}
    
    {% block title %}
    	Блог
    {% endblock %}
    
    {% block sidebar %}
    	{% block tags %}
    	{% endblock %}
    
    	{% block recent %}
    	{% endblock %}
    {% endblock %}
    


    Теперь приведем примеры внутренних страниц блога (все они наследуются от базовой страницы блога).

    Список статей:
    {% extend "blog/base.htm" %}
    
    {% block content %}
    	{% for article in article_list %}
    		«a href="{% url article_view article.id %}"»
    		{{ article.title }}
    		«/a»
    	{% endfor %}
    {% endblock %}
    



    Статья:
    {% extend "blog/base.htm" %}
    
    {% block title %}
    	{{ article.title }} - {{ block.super }}
    {% endblock %}
    
    {% block content %}
    	{{ article.text }}
    {% endblock %}
    



    Список статей, у которых есть определенный тег:
    {% extend "blog/index.htm" %}
    
    {% block title %}
    	{{ tag.title }} - {{ block.super }}
    {% endblock %}
    
    {% block content %}
    	{{ tag.title }}
    	{{ tag.text }}
    
    	{{ block.super }}
    {% endblock %}
    


    В данном случае, мы воспользовались еще одной хитростью. Ведь этот список ничем не отличается от простого списка статей — он просто отфильтрован по дополнительным параметрам. Поэтому мы унаследовали его от списка статей и при перекрытии тела использовали тег {{ block.super }} — вывести все содержимое родительского блока.

    Как видно, каждый шаблон очень конкретен и отвечает только за свою функциональность. Ему нет необходимости знать о всей странице в целом.

    Поклонники других шаблонных систем скажут, что для приведенного примера наследование не нужно. Действительно, то же самое можно реализовать, используя теги подстановки (include, ssi). Вот только логика и структура этих включений будет намного запутаннее. Получится, что статья должна знать, какие блоки будут на ее странице, и предоставлять данные для всех этих блоков. Тут на помощь приходит еще одна особенность Django — пользовательские теги.

    Пользовательские теги


    В нашем примере на странице статьи блога есть 7 блоков. Два из них — логотип и copyright — не нуждаются в данных. Для остальных пяти контроллеру необходимо предоставить шаблону данные. А именно:
    • заголовок статьи;
    • меню;
    • тело статьи;
    • список тегов;
    • последние статьи.


    Блоков могло быть намного больше, но непосредственное отношение к статье имеют только заголовок и тело статьи. Зачем статье знать, какие данные нужны этим блокам, откуда и как их получить? Абсолютно незачем — это не ее задача. Django предлагает нам следующее решение этой проблемы.

    Для каждого из блоков мы можем написать свой тег, состоящий из мини-контроллера и шаблона. Контроллер знает, как получить данные, шаблон — как отобразить. В том месте, где нам необходим блок, мы вставляем его тег — и все! Например, можно вставить список тегов и последних статей на главную страницу. Главной странице нет необходимости что-либо знать о структуре нашего блога — только факт наличия и имена тегов, реализуемых блогом.

    Вот пример тега для вывода списка последних статей в блоге:
    # тег
    @register.inclusion_tag('blog/article_recent_list.htm')
    def blog_recent_articles_list():
    	return {
    		'article_list': Article.objects.filter(public=True)[:10],
    	}
    
    # шаблон
    «h4»Последние статьи«/h4»
    «ul class="links"»
    	{% for article in article_list %}
    	«li»«a href="{% url article %}"»{{ article.title}}«/a»«/li»
    	{% endfor %}
    «/ul»
    


    Еще одним приемуществом такого подхода является то, что данные запрашиваются непосредственно при вставке тега. Если кэшировать несколько тегов, то будут кэшированы результаты их работы — повторно данные запрашиваться не будут! И не надо изобретать велосипеды, как тут ;)

    Понятно, что при аккуратном подходе то же самое можно реализовать без наследования и без пользовательских тегов — подключениями и вызовом функций. Главное приемущество Django — это стройная, логичная и стандартная сруктура решения таких проблем.

    Ссылки на официальную документацию:


    PS: Это перепечатка с моего блога http://dpp.su/. Кстати, там есть еще несколько менее интересных статей про Django.
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 43
    • +1
      Отличная статья. Сегодня вы меня прям все радуете (я имею в виду вас и статью про интеграцию дажнго в гугл апс энжин)=) Я уже с месяц потихоньку изучаю питон и джанго и любой хороший материал читается с интересом. А тут такой замечательный материал!
      Браво, жаль не могу дать плюшку.
      • +3
        уже с месяц потихоньку изучаю питон и джанго

        интересный момент который недавно отметили на конференции PyCon2008, который можно повсеместно наблюдать:
        Очень много людей которые подсели на Django до этого никогда не разрабатывали с помошью Python
        Браво ребятам с Djangoproject
        • +3
          К моему сожалению это правда: я не дооценивал красоту и прелесть Python'а до тех пор, пока не увидел бенчмарки фреймворков, где Django равал в колчья php'шных монстров. Потом покопав материалы по Python'у я обнаружил, что это именно то, о чем я очень долго мечтал - быстрый, изящный и объектно-ориентированный. А его возможности работы с нативными С библиотеками добавляют неповторимый шарм.
          Вообще идеология Pyhton'а и Django идут бок в бок - удобство и изящность, при этом не в убыток скорости.
          • +1
            На самом деле я делал сайты на Питоне (http://dpp.su/portfolio/tag/acesite3/) около полугода перед тем как начал изучать Django. Кроме этого делал сайты и на ПХП (http://dpp.su/portfolio/tag/php/), но при этом никакой фреймворк не использовал.
            Когда я решил посмотреть какие фреймворки для ПХП и для Питона существуют я перепробовал наверное с десяток. По-моему секрет успеха джанги в следующем:
            * хорошая скорость out-of-box (т.е. если при программировании придерживаться идеологии джанги то не придется танцевать с бубном вокруг своего детища после прихода десяти посетителей одновременно).
            * хороший quick start tutorial дающий представление обо всех частях системы.
            * хорошая документация - это по-моему самое главное (имхо, документация джанги намного лучше документации самого питона).
            * продуманная архитектура - практически ничего из написанного в документации не вызывает отторжения.
            * продуманная структура - как и архитектура достигается при помощи правильного использования общепринятых паттернов проектирования.
            Как я уже писал чуть выше:
            Главное приемущество Django - это стройная, логичная и стандартная сруктура решения проблем.

            Я допускаю, что для ПХП тоже есть грамотные фреймворки. Наверное, я их просто не нашел. Но с другой стороны - питон позволяет намного больше. Когда я только сел на питон - мне многое не нравилось - казалось, что на пхп аналогичные проблемы я бы решал намного эффективнее. Но со временем пришло понимание, что если простые вещи действительно проще сделать на пхп, то сложные сделать на нем красиво уже практически не реально. Простой пример - для удобного ORM нужна перегрузка операторов сравнения, а в пхп ее просто нет. (Кстати, в джанге ORM не очень удобный - многовато "магии".)
            • 0
              А в сторону ASP.NET не смотрели? Интересно узнать мнение профессионала с огромным опытом.
              • +1
                А зачем Microsoft, когда есть красивые бесплатные распространенные вещи?
                • +1
                  На самом деле - смысл есть. Точнее он может быть и надо оценивать в каждом конкретном случае.

                  Когда я работал в веб-студии "на потоке" я понял, что до какой-то степени в жертву скорости разработки можно принести очень многое. Пусть оно кривое, противное и тормозное, но если оно позволяет быстро сшибать деньги с неопытных клиентов - его надо использовать. Конечно халтура возможна только во время становления рынка (либо при монополии). А сколько и чего ты согласен принести в жертву - каждый решает сам. Мне, например, просто противно производить неликвид. И надо быть готовым, что Ваши клиенты могут очень быстро из Вас вырости (как из ползунков).
                  • 0
                    Никому не в обиду, просто у нас в стране по крайней мере, как мне кажется .NET web-разработчик получает больше, чем обычный web-разработчик. Понятно что фирмы и заказчики бывают разные, но в среднем ситуация помоему именно такая.

                    Собственно я сам писал на PHP почти 3 года, после чего ушел в мир .NET т.к. предложили больше денег.
                    • +1
                      ничего не могу сказать. я не пересекался с миром .NET и не интересовался ситуацией с зарплатами.

                      У меня есть только один знакомый дотнетовец. Да, он умеет рубить бабло. Но больше всего меня убило (прости, чувак, если эты это читаешь, но я запомнил это на всю жизнь) когда он не смог нарисовать блок-схему цикла. По-моему понимание основ это очень важно. То, что микрософт позволяет нам не думать о том как это устроено это конечно хорошо, но имхо это очень сильно отражается на качестве кода.

                      Оффтопик: а-а-а-а! ты предал свою аватарку! :)))
                      • 0
                        Нет ну цикл не уметь нарисовать это слишком... Помоему это умение уже не от платформ зависит.

                        Аватар не предал, с убунтой я всё-же играюсь :)
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • 0
                          Нет, тогда уж C++ и QT :)
                          • 0
                            мне тоже казалось что наибольшие зарплаты у жавы. наверное потому что основно потребитель - банки.

                            на счет зарплат тоже согласен. имхо, пока молодой и есть силы я лучше буду заниматься тем, что нравится. хороший специалист в любой области будет получать хорошую з/п. понятно, что в некоторых областях прийдется приложить намного больше усилий чтобы доказать что ты "хороший".
                            • НЛО прилетело и опубликовало эту надпись здесь
                    • +2
                      эээ... мне очень стыдно, но у меня есть против него предубеждение. если честно, то все, что я о нем знаю это то, что он существует.

                      С учетом этого приведу свои доводы:
                      * платный. у меня нет тысяч долларов на покупку windows server, mssql server, visual sudio, msdn и прочих продуктов микрософта. использовать ворованый софт и пытаться продать то что ты при помощи него сделал - получается как-то не очень.
                      * дорогой хостинг - менее распространен, выше требования.
                      * допустим я захотел его изучать. единственный верный путь - сделать на нем что-либо. что делать? сколько будет стоить хостинг и софт? а ведь первый блин наверняка будет комом...
                      * комьюнити. сама идеология opensource строится на бескорыстии и взаимопомощи. по-моему шанс получить бесплатную, но *квалифицированную* консультацию в случае opensource намного выше. да, размер комьюнити может быть больше - выучить проще, микрософт позаботился о комфорте разработчика - но каков средний уровень членов?
                      * уровень контроля. в opensource ты всегда можешь дойти до сути того как что-либо работает или почему что-то работает медленно. в случае с продуктами от мс - максимум до чего ты можешь "докопаться" - это до авторитетного высказывания, что "это лучше не использовать".

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

                      Вот и получается что ты пользуешся средствами разработки, а не разрабатываешь программы :)

                      это все мое имхо и я нарочно утрирую. не воспринимайте слишком серьезно.
                    • 0
                      та уже можно....
                      http://pecl.php.net/package/operator
                      • 0
                        спс, посмотрю.
                    • 0
                      Помоему таких результатов ребята "джанговцы" достигли благодаря стройности и логичности предлагаемых решений. Почти всегда есть простой и красивый one way to do it =)
                  • 0
                    В Django данные только pull'яться? о_О
                    • 0
                      Хм, я погорячился.
                      Другой вопрос - насколько логично плодить теги на каждый чих, и чем это лучше использования концепции компонентов, или тега cache и глобального сервиса?
                      • +1
                        Абсолютно логично
                        • 0
                          На второй вопрос не ответите? А то в упор не понимаю, как это кэшируется между разными запросами :(
                          • +1
                            Эээм. Мне сложно отвечать за автора :) Тему кэширования, он, конечно, не раскрыл. Видимо, начав писать про кэширование, dpp, пришел к выводу что вначале неплохо бы рассказать про джанго-шаблоны вообще.

                            Я думаю, он еще напишет пост :) Если не терпится, возможно эта ссылка чем то поможет, хотя я особо не тешу себя надеждой :)
                            • 0
                              спасибо что обратили внимание, а то бы так и не заметил )) я так увлекся описанием того как это устроено что забыл написать что "это".

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

                              сейчас попробую исправиться =)
                            • 0
                              Т.е. в данных примерах там вообще ничего не кэшируется.
                      • 0
                        Спасибо, очень кстати
                        • –4
                          Опять двадцать пять. Видно нравится изобретать велосипед :)
                          Блин есть массив данных
                          Путём рекурсивной функции получаем из него xml
                          Путём xslt - получаем из xml данных xhtml - шаблон.

                          Всё просто, достаточно написать пару функций. Изучить пару технологий. И куча всяких самопальных шаблонов не будет нужна :)
                          • +1
                            Да, нравится =) последний раз я этим занимался тут. Считаю, что велосипедостроение помогает понять структуру и архитектуру велосипедов "от производителя" лучше всего остального.

                            >Блин есть массив данных
                            По-моему один из нас чего-то недопонимает. Дело в том, что массива-то нету 8-(

                            Если из базы в xml доставать весть каталог товаров... сами понимаете что будет. Идея этих двух статей была именно в том, чтобы избавиться от выборки данных (которая может быть очень ресурсоемкой), но при этом не порушить целостность архитектуры.
                            • +2
                              Знаете, у меня есть ощущение, что если бы все было так хорошо, то все бы давно так давно делали.
                              • 0
                                Заставлять простых людей писать шаблоны на xslt? Заставлять программистов всё переводить в xml? Да вы, батенька, садист! :)
                                • НЛО прилетело и опубликовало эту надпись здесь
                                • 0
                                  Э, нет, не о том мой "велосипед" был!
                                  У меня там вместо этих блоков было бы $this->render_action('list', 'article');
                                  Это не то.
                                  Покажите-ка, пожалуйста, кэширование списка статей на странице списка статей. Вот на blog/index.htm в Вашем примере.
                                  • 0
                                    Извиняюсь, Вы правы. Как я уже заметил тут я увлекся и не описал кеширование совсем. Обещаю вскоре написать статью о кешировании в джанге. Сейчас, к сожалению, совсем пропало время. Может в выходные?
                                    • 0
                                      как и обещал - написал статью про кэширование. тут.
                                    • 0
                                      за иллюстрации к посту большое спасибо, очень наглядно получилось. ждём раскрытия темы кеширования, тоже с картинками)
                                      • 0
                                        Картинки уже нарисовал 8) но статью писать пока нет времени. Думаю займусь в выходные.
                                      • 0
                                        спасибо большое за статью!
                                        • 0
                                          Оффтопик:
                                          Хабралюди! Чем вы кормите мои комментарии? Никак не могу понять почему джанга срыгивает некоторые из них.

                                          Если у Вас не получилось отправить какой-то комментарий прошу написать мне об этом по хабропочте или на dpp at dpp.su. Спасибо.
                                          • 0
                                            Для тех кто хочет использовать шаблонизаторы с наследованием под Питон, но не в контексте Джанго - есть такая штука как Mako Templates
                                            • 0
                                              После одного проекта на Джанге второй я начал с того, что прикрутил Mako.. Если верстальщик адекватный — имхо это самый правильный выбор
                                              • 0
                                                Спс, попробую.
                                              • 0
                                                Отлично, что вместо перевода документации, вы решили показать много-много реальных примеров в доступной форме :) Хоть вещи и простые, но спасибо, мой приятель будет рад, он как раз на наследовании застрял.
                                                • 0
                                                  Одной из мотивационных причин написанию статьи для меня стало то, что в свое время мне пытались объяснить самописанную систему наследования шаблонов. Вещи действительно простые, но это зависит от того как объяснять... Тогда я несколько дней не мог всасать чего он там наворотил...

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