Spec-Zone.ru › Django 2.1

Язык шаблонов 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.items %}
    Do something with k and v here...
{% endfor %}

Из-за того, что поиск по словарю происходит в первую очередь, это поведение вступает в силу и предоставляет значение по умолчанию вместо использования предназначенного .items() метода. В этом случае рассмотрите возможность предварительного преобразования в словарь.

В приведенном выше примере {{ 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 admin.

Теги

Теги выглядят так: {% 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 admin.

Комментарии

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

Например, этот шаблон будет отображен как '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»), так как они уже были экранированы, если это необходимо, в родительском шаблоне.
  • Переменные, созданные вне блока {% block %} с использованием синтаксиса тега шаблона as , нельзя использовать внутри блока. Например, этот шаблон ничего не рендерит:

    {% trans "Title" as title %}
    {% block content %}{{ title }}{% endblock %}
    
  • Для повышения читабельности вы можете присвоить тегу {% endblock %} необязательное имя. Например:

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

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

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

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

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

Hello, {{ name }}

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

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

С таким значением имени шаблон будет рендериться как:

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

…что означает, что браузер откроет окно с предупреждением JavaScript!

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

<b>username

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

Hello, <b>username

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

Очевидно, что данные, введённые пользователем, не должны слепо доверяться и вставляться непосредственно в ваши веб-страницы, потому что злонамеренный пользователь может использовать подобную дыру для совершения потенциально вредных действий. Такой тип уязвимости безопасности называется атакой Cross Site Scripting (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 как сокращение от безопасного от дальнейшего экранирования или может быть безопасно интерпретирован как 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, точно так же, как и все теги блоков. Например:

base.html
{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}
child.html
{% 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 не влияет на автоматически экранированные переменные.

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

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

{{ 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 }}

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

models.py
class Task(models.Model):
    def foo(self):
        return "bar"
template.html
{{ 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/2.1/ref/templates/language/

Spec-Zone.ru

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