Spec-Zone.ru › Django 1.10

Язык шаблонов Django

В данном документе описывается синтаксис языка системы шаблонов Django. Если вы ищете более технический взгляд на то, как она работает и как ее расширить, см. Язык шаблонов Django: для программистов Python.

Язык шаблонов Django разработан для достижения баланса между мощностью и простотой. Он разработан так, чтобы быть удобным для тех, кто привык работать с HTML. Если у вас есть опыт работы с другими текстовыми языками шаблонов, такими как Smarty или Jinja2, вы должны чувствовать себя как дома с шаблонами Django.

Философия

Если вы имеете опыт программирования или привыкли к языкам, которые смешивают код программирования непосредственно в HTML, помните, что система шаблонов Django не просто встраивает Python в HTML. Это сделано по умолчанию: система шаблонов предназначена для выражения представления, а не логики программы.

Система шаблонов Django предоставляет теги, которые работают аналогично некоторым конструкциям программирования – тег if для логических проверок, тег for для циклов и т. д. – но они не просто выполняются как соответствующий код Python, и система шаблонов не будет выполнять произвольные выражения Python. По умолчанию поддерживаются только теги, фильтры и синтаксис, перечисленные ниже (хотя вы можете добавлять собственные расширения к языку шаблонов по мере необходимости).

Шаблоны

Шаблон — это просто текстовый файл. Он может генерировать любой текстовый формат (HTML, XML, CSV и т. д.).

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

Ниже приведен минимальный шаблон, который иллюстрирует несколько основ. Каждый элемент будет объяснен позже в этом документе.

{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}

Философия

Почему использовать текстовый шаблон вместо XML-шаблона (например, Zope’s TAL)? Мы хотели, чтобы язык шаблонов Django был пригоден не только для шаблонов XML/HTML. В World Online мы используем его для писем, JavaScript и CSV. Вы можете использовать язык шаблонов для любого текстового формата.

Ах, и еще кое-что: заставлять людей редактировать XML — это садизм!

Переменные

Переменные выглядят так: {{ variable }}. Когда движок шаблонов встречает переменную, он оценивает эту переменную и заменяет ее результатом. Имена переменных состоят из любой комбинации буквенно-цифровых символов и символа подчеркивания ("_"). Точка ("." ) также появляется в разделах переменных, хотя это имеет особое значение, как указано ниже. Важно, что вы не можете использовать пробелы или знаки препинания в именах переменных.

Используйте точку (. ), чтобы получить доступ к атрибутам переменной.

За кулисами

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

  • Поиск по словарю
  • Поиск атрибута или метода
  • Поиск по числовому индексу

Если полученное значение является вызываемым, оно вызывается без аргументов. Результат вызова становится значением шаблона.

Этот порядок поиска может привести к некоторым неожиданным результатам с объектами, которые переопределяют поиск по словарю. Например, рассмотрим следующий фрагмент кода, который пытается пройти цикл по collections.defaultdict.

{% for k, v in defaultdict.iteritems %}
    Do something with k and v here...
{% endfor %}

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

В приведенном выше примере {{ section.title }} будет заменено на title атрибут объекта section.

Если используется несуществующая переменная, система шаблонов вставит значение опции string_if_invalid, которое по умолчанию равно '' (пустая строка).

Обратите внимание, что «bar» в выражении шаблона, таком как {{ foo.bar }} , будет интерпретироваться как буквальная строка, а не как значение переменной «bar», если она существует в контексте шаблона.

Фильтры

Вы можете изменить переменные для отображения, используя фильтры.

Фильтры выглядят так: {{ name|lower }}. Это отображает значение переменной {{ name }} после фильтрации с помощью фильтра lower, который преобразует текст в нижний регистр. Используйте символ | (|) для применения фильтра.

Фильтры могут быть «цепными». Выход одного фильтра применяется к следующему. {{ text|escape|linebreaks }} — это распространенный метод для экранирования содержимого текста и преобразования символов перевода строки в теги <p>.

Некоторые фильтры принимают аргументы. Аргумент фильтра выглядит так: {{ bio|truncatewords:30 }}. Это отобразит первые 30 слов переменной bio.

Аргументы фильтров, содержащие пробелы, должны быть заключены в кавычки; например, чтобы объединить список запятыми и пробелами, вы бы использовали {{ list|join:", " }}.

Django предоставляет около шестидесяти встроенных фильтров шаблонов. Вы можете прочитать обо всех них в справочнике встроенных фильтров. Чтобы дать вам представление о том, что доступно, вот некоторые из наиболее часто используемых фильтров шаблонов:

default

Если переменная ложная или пустая, используйте заданный по умолчанию. В противном случае используйте значение переменной. Например:

{{ value|default:"nothing" }}

Если value не предоставлено или пусто, выше будет отображено «nothing».

length

Возвращает длину значения. Это работает как для строк, так и для списков. Например:

{{ value|length }}

Если value равно ['a', 'b', 'c', 'd'], вывод будет 4.

filesizeformat

Форматирует значение как «человекочитаемый» размер файла (например, '13 KB', '4.1 MB', '102 bytes', и т. д.). Например:

{{ value|filesizeformat }}

Если value равно 123456789, вывод будет 117.7 MB.

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

Вы также можете создавать собственные пользовательские фильтры шаблонов; см. Пользовательские теги и фильтры шаблонов.

См. также

Интерфейс администрирования Django может включать полную справку по всем тегам и фильтрам шаблонов, доступным для данного сайта. См. Документатор администрирования Django.

Теги

Теги выглядят так: {% tag %}. Теги сложнее, чем переменные: некоторые создают текст в выводе, некоторые управляют потоком, выполняя циклы или логические операции, а некоторые загружают внешнюю информацию в шаблон для использования последующими переменными.

Некоторые теги требуют начального и конечного тегов (например, {% tag %} ... tag contents ... {% endtag %}).

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

for

Проходит по каждому элементу массива. Например, чтобы отобразить список спортсменов, предоставленных в athlete_list:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>
if, elif, and else

Оценивает переменную, и если эта переменная «истинна», содержимое блока отображается:

{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
    Athletes should be out of the locker room soon!
{% else %}
    No athletes.
{% endif %}

В приведенном выше примере, если athlete_list не пуста, количество спортсменов будет отображаться переменной {{ athlete_list|length }} . В противном случае, если athlete_in_locker_room_list не пуста, будет отображаться сообщение «Спортсмены должны быть…». Если оба списка пусты, будет отображено «Спортсменов нет».

Вы также можете использовать фильтры и различные операторы в теге if:

{% if athlete_list|length > 1 %}
   Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
   Athlete: {{ athlete_list.0.name }}
{% endif %}

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

block and extends
Настройка наследования шаблонов (см. ниже), мощный способ сокращения «шаблонов» в шаблонах.

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

Вы также можете создавать собственные пользовательские теги шаблонов; см. Пользовательские теги и фильтры шаблонов.

См. также

Интерфейс администрирования Django может включать полную справку по всем тегам и фильтрам шаблонов, доступным для данного сайта. См. Документатор администрирования Django.

Комментарии

Чтобы прокомментировать часть строки в шаблоне, используйте синтаксис комментария: {# #}.

Например, этот шаблон будет отображаться как 'hello':

{# greeting #}hello

Комментарий может содержать любой код шаблона, правильный или нет. Например:

{# {% if foo %}bar{% else %} #}

Этот синтаксис может быть использован только для однострочных комментариев (переводы строк не допускаются между разделителями {# и #}). Если вам нужно прокомментировать многострочный фрагмент шаблона, см. тег comment.

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

Самая мощная и, следовательно, самая сложная часть движка шаблонов Django — наследование шаблонов. Наследование шаблонов позволяет создавать базовый шаблон-«каркас», содержащий все общие элементы сайта и определяющий блоки, которые дочерние шаблоны могут переопределять.

Наследование шаблонов легче всего понять, начав с примера:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}My amazing site{% endblock %}</title>
</head>

<body>
    <div id="sidebar">
        {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
        {% endblock %}
    </div>

    <div id="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

Этот шаблон, который мы назовём base.html, определяет простой HTML-шаблон документа, который можно использовать для простой страницы с двумя колонками. Задача «дочерних» шаблонов — заполнить пустые блоки содержимым.

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

Дочерний шаблон может выглядеть так:

{% extends "base.html" %}

{% block title %}My amazing blog{% endblock %}

{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>
    <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

Ключевым здесь является тег extends. Он сообщает движку шаблонов, что этот шаблон «расширяет» другой шаблон. При обработке системы шаблонов этот шаблон сначала ищет родительский шаблон — в данном случае «base.html».

В этот момент движок шаблонов заметит три тега block в base.html и заменит эти блоки содержимым дочернего шаблона. В зависимости от значения blog_entries, вывод может выглядеть так:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>My amazing blog</title>
</head>

<body>
    <div id="sidebar">
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    </div>

    <div id="content">
        <h2>Entry one</h2>
        <p>This is my first entry.</p>

        <h2>Entry two</h2>
        <p>This is my second entry.</p>
    </div>
</body>
</html>

Обратите внимание, что поскольку дочерний шаблон не определил блок sidebar, используется значение из родительского шаблона. Содержимое внутри тега {% block %} в родительском шаблоне всегда используется в качестве резервного варианта.

Вы можете использовать столько уровней наследования, сколько нужно. Один из распространённых способов использования наследования — следующая трёхступенчатая схема:

  • Создайте шаблон base.html, который содержит общий вид вашего сайта.
  • Создайте шаблон base_SECTIONNAME.html для каждого «раздела» вашего сайта. Например, base_news.html, base_sports.html. Эти шаблоны расширяют шаблон base.html и включают специфичные для раздела стили/дизайн.
  • Создайте отдельные шаблоны для каждого типа страницы, например, новости или записи блога. Эти шаблоны расширяют соответствующий шаблон раздела.

Этот подход максимизирует повторное использование кода и упрощает добавление элементов в общие области содержимого, такие как навигация по всему разделу.

Вот несколько советов по работе с наследованием:

  • Если вы используете {% extends %} в шаблоне, он должен быть первым тегом шаблона. Иначе наследование шаблонов не сработает.
  • Больше тегов {% block %} в ваших базовых шаблонах — лучше. Помните, что дочерние шаблоны не обязаны определять все родительские блоки, поэтому вы можете заполнить разумные значения в ряде блоков, а затем определить только необходимые позже. Лучше иметь больше маркеров, чем меньше.
  • Если вы обнаруживаете, что дублируете содержимое в нескольких шаблонах, это, вероятно, означает, что вам следует перенести это содержимое в {% block %} в родительском шаблоне.
  • Если вам нужно получить содержимое блока из родительского шаблона, переменная {{ block.super }} поможет. Это полезно, если вы хотите добавить к содержимому родительского блока, а не полностью переопределять его. Данные, вставленные с помощью {{ block.super }}, не будут автоматически экранированы (см. следующую секцию «Автоматическое экранирование HTML»), так как они уже были экранированы, если это необходимо, в родительском шаблоне.
  • Для повышения читаемости вы можете присвоить имя вашему тегу {% endblock %}. Например:

    {% block content %}
    ...
    {% endblock content %}
    

    В более крупных шаблонах эта техника помогает увидеть, какие теги {% block %} закрываются.

И наконец, обратите внимание, что вы не можете определить несколько тегов block с одинаковым именем в одном шаблоне. Это ограничение существует, потому что тег блока работает «в обоих» направлениях. То есть тег блока не просто предоставляет место для заполнения — он также определяет содержимое, которое заполняет это место в родительском шаблоне. Если в шаблоне были два тега block с одинаковым именем, родительский шаблон не знал бы, какой из блоков использовать.

Автоматическое экранирование HTML

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

Hello, {{ name }}

На первый взгляд, это безобидный способ отображения имени пользователя, но представьте, что произойдёт, если пользователь введёт своё имя так:

<script>alert('hello')</script>

При таком значении имени шаблон будет отображен как:

Hello, <script>alert('hello')</script>

…что означает, что браузер откроет окно JavaScript alert!

Аналогично, что если имя содержало символ '<'?

<b>username

Это приведёт к отображению шаблона так:

Hello, <b>username

…что, в свою очередь, приведёт к тому, что остальная часть веб-страницы будет выделена жирным шрифтом!

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

Чтобы избежать этой проблемы, у вас есть два варианта:

  • Во-первых, вы можете убедиться, что каждая недоверенная переменная проходит через фильтр escape (документирован ниже), который преобразует потенциально вредные символы HTML в безопасные. Это было стандартным решением в Django в первые годы его существования, но проблема в том, что это возлагает ответственность на вас, разработчика/автора шаблона, убедиться, что всё экранировано. Легко забыть экранировать данные.
  • Во-вторых, вы можете воспользоваться автоматическим экранированием HTML Django. Остальная часть этого раздела описывает, как работает автоматическое экранирование.

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

  • < преобразуется в &lt;
  • > преобразуется в &gt;
  • ' (одинарная кавычка) преобразуется в &#39;
  • " (двойная кавычка) преобразуется в &quot;
  • & преобразуется в &amp;

Ещё раз подчеркнём, что это поведение включено по умолчанию. Если вы используете систему шаблонов Django, вы защищены.

Как отключить

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

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

Для отдельных переменных

Чтобы отключить автоматическое экранирование для отдельной переменной, используйте фильтр safe:

This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}

Представьте, что safe — это сокращение от safe from further escaping или может безопасно интерпретироваться как HTML. В этом примере, если data содержит '<b>', вывод будет:

This will be escaped: &lt;b&gt;
This will not be escaped: <b>

Для блоков шаблонов

Чтобы управлять автоматическим экранированием для шаблона, оберните шаблон (или только определённый раздел шаблона) в тег autoescape, как показано ниже:

{% autoescape off %}
    Hello {{ name }}
{% endautoescape %}

Тег autoescape принимает аргумент on или off. Иногда вы можете захотеть принудительно включить автоматическое экранирование, когда оно было отключено. Вот пример шаблона:

Auto-escaping is on by default. Hello {{ name }}

{% autoescape off %}
    This will not be auto-escaped: {{ data }}.

    Nor this: {{ other_data }}
    {% autoescape on %}
        Auto-escaping applies again: {{ name }}
    {% endautoescape %}
{% endautoescape %}

Тег автоматического экранирования передает своё действие шаблонам, которые расширяют текущий, а также шаблонам, включённым с помощью тега include, как и все теги блоков. Например:

{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}
{% extends "base.html" %}
{% block title %}This &amp; that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}

Поскольку автоматическое экранирование выключено в базовом шаблоне, оно также будет выключено в дочернем шаблоне, что приведёт к следующему HTML-выводу, когда переменная greeting содержит строку <b>Hello!</b>.

<h1>This &amp; that</h1>
<b>Hello!</b>

Примечания

Как правило, авторам шаблонов не нужно сильно беспокоиться об автоматическом экранировании. Разработчикам на стороне Python (людям, которые пишут представления и пользовательские фильтры) нужно учитывать случаи, когда данные не должны быть экранированы, и соответствующим образом помечать данные, чтобы всё работало в шаблоне.

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

Строковые литералы и автоматическое экранирование

Как мы уже упоминали ранее, аргументы фильтров могут быть строками:

{{ data|default:"This is a string literal." }}

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

Это означает, что вы напишете

{{ data|default:"3 &lt; 2" }}

…а не:

{{ data|default:"3 < 2" }}  {# Bad! Don't do this. #}

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

Доступ к вызовам методов

Большинство вызовов методов, прикреплённых к объектам, также доступны внутри шаблонов. Это означает, что шаблоны имеют доступ к гораздо большему, чем просто атрибуты класса (например, имена полей) и переменные, переданные из представлений. Например, Django ORM предоставляет синтаксис “entry_set” для поиска коллекции объектов, связанных по внешнему ключу. Таким образом, задавая модель под названием «comment» с внешним ключом, связанным с моделью «task», вы можете перебрать все комментарии, прикреплённые к заданной задаче, так:

{% for comment in task.comment_set.all %}
    {{ comment }}
{% endfor %}

Аналогично, QuerySets предоставляют метод count() для подсчёта количества содержащихся в них объектов. Таким образом, вы можете получить счётчик всех комментариев, связанных с текущей задачей, с помощью:

{{ task.comment_set.all.count }}

И, конечно же, вы можете легко получить доступ к методам, которые вы явно определили в своих собственных моделях:

class Task(models.Model):
    def foo(self):
        return "bar"
{{ task.foo }}

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

Библиотеки пользовательских тегов и фильтров

Некоторые приложения предоставляют библиотеки пользовательских тегов и фильтров. Чтобы получить к ним доступ в шаблоне, убедитесь, что приложение находится в INSTALLED_APPS (в этом примере мы добавим 'django.contrib.humanize'), а затем используйте тег load в шаблоне:

{% load humanize %}

{{ 45000|intcomma }}

В приведённом выше примере тег load загружает библиотеку тегов humanize, которая затем делает фильтр intcomma доступным для использования. Если вы включили django.contrib.admindocs, вы можете обратиться к документации в своём административном интерфейсе, чтобы найти список пользовательских библиотек в вашей установке.

Тег load может принимать несколько имён библиотек, разделённых пробелами. Пример:

{% load humanize i18n %}

См. Пользовательские теги и фильтры шаблонов для получения информации о создании собственных пользовательских библиотек шаблонов.

Пользовательские библиотеки и наследование шаблонов

При загрузке пользовательской библиотеки тегов или фильтров теги/фильтры доступны только для текущего шаблона — а не для родительских или дочерних шаблонов вдоль пути наследования шаблонов.

Например, если шаблон foo.html имеет {% load humanize %}, дочерний шаблон (например, шаблон с {% extends "foo.html" %}) не будет иметь доступа к тегам и фильтрам шаблона humanize. Дочерний шаблон отвечает за свои собственные {% load humanize %}.

Это функция, направленная на поддержание надёжности и здравомыслия.

См. также

Справочник по шаблонам
Охватывает встроенные теги, встроенные фильтры, использование альтернативного шаблона, языка и многое другое.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.10/ref/templates/language/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API