Язык шаблонов 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 предоставляет около шестидесяти встроенных фильтров. Вы можете прочитать о них в разделе о встроенных фильтрах. Чтобы дать вам представление о возможностях, вот некоторые из наиболее часто используемых фильтров:
defaultIf a variable is false or empty, use given default. Otherwise, use the value of the variable. For example:
{{ value|default:"nothing" }}
Если
valueравно""(пустая строка), будет выведеноnothing.lengthReturns 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.
Комментарии¶
Чтобы закомментировать строку в шаблоне, используйте синтаксис комментариев: {# #}.
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 tagassyntax 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, каждый шаблон экранирует все переменные. В частности выполняются такие замены:
<заменяется на<>заменяется на>'(одинарная кавычка) заменяется на'"(двойная кавычка) заменяется на"&заменяется на&
Опять же, мы подчеркиваем, что такое поведение используется по умолчанию. Если вы используете систему шаблонов 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: <b>
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 & 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 & 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 < 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».
См.также
- Описание системы шаблонов
Охватывает встроенные теги, встроенные фильтры, использование альтернативного языка шаблонов и многое другое.