• 3.1
  • 5.0
  • 6.1
  • Версия документации: 3.2

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

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

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

Философия

Если у вас есть опыт программирования или вы использовали PHP, который позволяет интегрировать программный код прямо 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 (например, TAL от Zope)? Мы хотели, чтобы язык шаблонов Django можно было использовать не только для шаблонов XML/HTML. Вы можете использовать язык шаблонов для любого текстового формата, такого как электронные письма, JavaScript и CSV.

Переменные

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

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

За кулисами

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

  • Ключ словаря

  • Атрибут или метод

  • Индекс списка

Если найден вызываемый объект(функция или метод), он будет вызван без аргументов. Результат будет использоваться шаблоном как значение.

This lookup order can cause some unexpected behavior with objects that override dictionary lookup. For example, consider the following code snippet that attempts to loop over a 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», а не переменная с названием «bar».

Атрибуты переменных, начинающиеся с подчеркивания, могут быть недоступны, поскольку они обычно считаются частными.

Фильтры

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

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

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

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

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

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

default

If a variable is false or empty, use given default. Otherwise, use the value of the variable. For example:

{{ value|default:"nothing" }}

Если value равно "" (пустая строка), будет выведено nothing.

length

Returns the length of the value. This works for both strings and lists. For example:

{{ value|length }}

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

filesizeformat

Formats the value like a «human-readable» file size (i.e. '13 KB', '4.1 MB', '102 bytes', etc.). For example:

{{ value|filesizeformat }}

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

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

Вы можете создать собственный фильтр; смотрите Custom template tags and filters.

См.также

Интерфейс администратора Django может предоставить полный список доступных тегов и фильтров. Смотрите Генератор документации администратора Django.

Теги

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

Некоторые теги требуют открывающий и закрывающий теги (например, {% tag %} ... содержимое тега ... {% endtag %}).

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

for

Loop over each item in an array. For example, to display a list of athletes provided in athlete_list:

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

Evaluates a variable, and if that variable is «true» the contents of the block are displayed:

{% 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 не пустой, будет показано сообщение «Athletes should be out…». Если оба списка пустые, будет показано сообщение «No athletes.».

You can also use filters and various operators in the if tag:

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

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

block и extends

Определяет наследование шаблонов (смотрите ниже), эффективный способ использовать шаблоны.

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

Вы можете создать собственный тег; смотрите Custom template tags and filters.

См.также

Интерфейс администратора Django может предоставить полный список доступных тегов и фильтров. Смотрите Генератор документации администратора Django.

Комментарии

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

For example, this template would render as 'hello':

{# greeting #}hello

A comment can contain any template code, invalid or not. For example:

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

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

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

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

Let’s look at template inheritance by starting with an example:

<!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 – указывает механизму шаблонов, какая часть шаблона может быть переопределена в дочернем шаблоне.

A child template might look like this:

{% 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».

At that point, the template engine will notice the three block tags in base.html and replace those blocks with the contents of the child template. Depending on the value of blog_entries, the output might look like:

<!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 %} в вашем шаблоне, тем лучше. Помните, дочерний шаблон не обязан определять все блоки родительского, вы можете указать значение по умолчанию для всех блоков, а затем определить в дочернем шаблоне только те, которые необходимы. Лучше иметь больше «hooks», чем меньше «hooks».

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

  • Если вам необходимо содержимое блока родительского шаблона, используйте переменную {{ block.super }}. Эта полезно, если вам необходимо дополнить содержимое родительского блока, а не полностью переопределить его. Содержимое {{ block.super }} не будет автоматически экранировано (смотрите раздел ниже), так как оно уже было экранировано, при необходимости, в родительском шаблоне.

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

  • Variables created outside of a {% block %} using the template tag as syntax can’t be used inside the block. For example, this template doesn’t render anything:

    {% translate "Title" as title %}
    {% block content %}{{ title }}{% endblock %}
    
  • For extra readability, you can optionally give a name to your {% endblock %} tag. For example:

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

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

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

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

When generating HTML from templates, there’s always a risk that a variable will include characters that affect the resulting HTML. For example, consider this template fragment:

Hello, {{ name }}

At first, this seems like a harmless way to display a user’s name, but consider what would happen if the user entered their name as this:

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

With this name value, the template would be rendered as:

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

…что приведет к отображению alert-окна JavaScript!

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

<b>username

That would result in a rendered template like this:

Hello, <b>username

…which, in turn, would result in the remainder of the Web page being bolded!

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

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

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

  • Второй, вы можете позволить Django автоматически экранировать HTML. Оставшаяся часть этого раздела описывает, как автоматическое экранирование работает.

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

  • < заменяется на &lt;

  • > заменяется на &gt;

  • ' (одинарная кавычка) заменяется на &#39;

  • " (двойная кавычка) заменяется на &quot;

  • & заменяется на &amp;

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

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

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

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

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

To disable auto-escaping for an individual variable, use the safe filter:

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

Think of safe as shorthand for safe from further escaping or can be safely interpreted as HTML. In this example, if data contains '<b>', the output will be:

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

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

To control auto-escaping for a template, wrap the template (or a particular section of the template) in the autoescape tag, like so:

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

The autoescape tag takes either on or off as its argument. At times, you might want to force auto-escaping when it would otherwise be disabled. Here is an example template:

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

Тег autoescape распространяет свой эффект на шаблоны, которые наследуют текущий, и на включенные тегом 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 %}

Because auto-escaping is turned off in the base template, it will also be turned off in the child template, resulting in the following rendered HTML when the greeting variable contains the string <b>Hello!</b>:

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

Заметки

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

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

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

As we mentioned earlier, filter arguments can be strings:

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

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

This means you would write

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

…rather than:

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

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

Вызов методов

Most method calls attached to objects are also available from within templates. This means that templates have access to much more than just class attributes (like field names) and variables passed in from views. For example, the Django ORM provides the «entry_set» syntax for finding a collection of objects related on a foreign key. Therefore, given a model called «comment» with a foreign key relationship to a model called «task» you can loop through all comments attached to a given task like this:

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

Similarly, QuerySets provide a count() method to count the number of objects they contain. Therefore, you can obtain a count of all comments related to the current task with:

{{ task.comment_set.all.count }}

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

models.py
class Task(models.Model):
    def foo(self):
        return "bar"
шаблон.html
{{ task.foo }}

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

Собственные библиотеки тегов и фильтров

Certain applications provide custom tag and filter libraries. To access them in a template, ensure the application is in INSTALLED_APPS (we’d add 'django.contrib.humanize' for this example), and then use the load tag in a template:

{% load humanize %}

{{ 45000|intcomma }}

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

The load tag can take multiple library names, separated by spaces. Example:

{% load humanize i18n %}

Смотрите раздел Custom template tags and filters, чтобы узнать как создавать собственные библиотеки для шаблонов.

Собственные библиотеки и наследование шаблонов

При загрузке библиотеки, теги и фильтры, которые она содержит, будут доступны только в текущем шаблоне – не в родительском или дочернем шаблонах.

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

Так сделано ради «maintainability» и «sanity».

См.также

Описание системы шаблонов

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

Back to Top