Шаблоны
Как веб-фреймворк, Django нуждается в удобном способе динамически генерировать HTML. Наиболее распространённый подход основан на шаблонах. Шаблон содержит статическую часть желаемого HTML-вывода, а также специальный синтаксис, описывающий, как будет вставлено динамическое содержимое. Для практического примера создания HTML-страниц с шаблонами, см. Урок 3.
Проект Django может быть настроен с одним или несколькими движками шаблонов (или даже нулём, если вы не используете шаблоны). Django поставляется с встроенными бэкендами для собственной системы шаблонов, творчески названной языком шаблонов Django (DTL), и для популярной альтернативы Jinja2. Бэкэнды для других языков шаблонов могут быть доступны от сторонних разработчиков. Вы также можете написать свой собственный пользовательский бэкенд, см. Пользовательский бэкенд шаблонов
Django определяет стандартный API для загрузки и рендеринга шаблонов независимо от бэкенда. Загрузка заключается в поиске шаблона для данного идентификатора и его предварительной обработке, обычно компиляции его в представление в оперативной памяти. Рендеринг означает интерполяцию шаблона с данными контекста и возвращение полученной строки.
Язык шаблонов Django — собственная система шаблонов Django. До Django 1.8 это был единственный доступный встроенный вариант. Это хорошая библиотека шаблонов, хотя она довольно предвзятая и имеет несколько особенностей. Если у вас нет веских причин выбрать другой бэкенд, вы должны использовать DTL, особенно если вы пишете подключаемый модуль и планируете распространять шаблоны. Приложения Django contrib, которые включают шаблоны, такие как django.contrib.admin, используют DTL.
По историческим причинам как общая поддержка движков шаблонов, так и реализация языка шаблонов Django находятся в пространстве имён django.template.
Предупреждение
Система шаблонов не защищена от ненадежных авторов шаблонов. Например, сайт не должен разрешать своим пользователям предоставлять свои собственные шаблоны, так как авторы шаблонов могут делать такие вещи, как осуществлять атаки XSS и получать доступ к свойствам переменных шаблонов, которые могут содержать конфиденциальную информацию.
Язык шаблонов Django
Синтаксис
О данной секции
Это обзор синтаксиса языка шаблонов Django. Для подробностей см. справочник по синтаксису языка.
Шаблон Django — это текстовый документ или строка Python, помеченные с использованием языка шаблонов Django. Некоторые конструкции распознаются и интерпретируются движком шаблонов. Основные из них — переменные и теги.
Шаблон рендерится с контекстом. Рендеринг заменяет переменные их значениями, которые ищутся в контексте, и выполняет теги. Всё остальное выводится как есть.
Синтаксис языка шаблонов Django включает четыре конструкции.
Переменные
Переменная выводит значение из контекста, который является объектом, подобным словарю, сопоставляющим ключи со значениями.
Переменные заключены в {{ и }} так:
My first name is {{ first_name }}. My last name is {{ last_name }}.
При контексте {'first_name': 'John', 'last_name': 'Doe'}, этот шаблон рендерится в:
My first name is John. My last name is Doe.
Обращение к элементу словаря, обращение к атрибуту и обращение к индексу списка реализуются с помощью нотации точки:
{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}
Если переменная отображается в вызываемый объект, система шаблонов вызовет его без аргументов и будет использовать его результат вместо вызываемого объекта.
Теги
Это определение намеренно расплывчато. Например, тег может выводить содержимое, служить в качестве управляющей структуры, например, оператора «if» или цикла «for», извлекать содержимое из базы данных или даже предоставлять доступ к другим тегам шаблонов.
Теги заключены в {% и %} так:
{% csrf_token %}
Большинство тегов принимают аргументы:
{% cycle 'odd' 'even' %}
Некоторые теги требуют начального и конечного тегов:
{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}
Доступна ссылка на встроенные теги, а также инструкции по написанию пользовательских тегов.
Фильтры
Фильтры преобразуют значения переменных и аргументов тегов.
Они выглядят так:
{{ django|title }}
При контексте {'django': 'the web framework for perfectionists with
deadlines'}, этот шаблон рендерится в:
The Web Framework For Perfectionists With Deadlines
Некоторые фильтры принимают аргумент:
{{ my_date|date:"Y-m-d" }}
Доступна ссылка на встроенные фильтры, а также инструкции по написанию пользовательских фильтров.
Комментарии
Комментарии выглядят так:
{# this won't be rendered #}
Тег {% comment %} обеспечивает многострочные комментарии.
Компоненты
О данной секции
Это обзор API языка шаблонов Django. Для подробностей см. справочник по API.
Движок
django.template.Engine инкапсулирует экземпляр системы шаблонов Django. Основная причина непосредственного создания экземпляра Engine заключается в использовании языка шаблонов Django вне проекта Django.
django.template.backends.django.DjangoTemplates — это тонкий обертка, адаптирующая django.template.Engine к API бэкенда шаблонов Django.
Шаблон
django.template.Template представляет собой скомпилированный шаблон. Шаблоны получаются с помощью Engine.get_template() или Engine.from_string().
Аналогично, django.template.backends.django.Template — это тонкий обертка, адаптирующая django.template.Template к общему API шаблонов.
Контекст
django.template.Context хранит метаданные помимо данных контекста. Он передаётся в Template.render() для рендеринга шаблона.
django.template.RequestContext является подклассом Context, который хранит текущий HttpRequest и выполняет обработчики контекста шаблона.
В общем API нет эквивалентной концепции. Данные контекста передаются в обычном dict, а текущий HttpRequest передаётся отдельно, если это необходимо.
Загрузчики
Загрузчики шаблонов отвечают за поиск шаблонов, их загрузку и возврат объектов Template.
Django предоставляет несколько встроенных загрузчиков шаблонов и поддерживает пользовательские загрузчики шаблонов.
Обработчики контекста
Обработчики контекста — это функции, которые получают текущий HttpRequest в качестве аргумента и возвращают dict данных, которые должны быть добавлены в контекст рендеринга.
Их основное назначение — добавление общих данных, используемых всеми шаблонами, в контекст, не дублируя код в каждом представлении.
Django предоставляет множество встроенных обработчиков контекста, и вы также можете реализовать собственные дополнительные обработчики контекста.
Поддержка движков шаблонов
Настройка
Движки шаблонов настраиваются с помощью настройки TEMPLATES. Это список конфигураций, по одной на каждый движок. Значение по умолчанию — пустой список. Значение settings.py сгенерированное командой startproject определяет более полезное значение:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
# ... some options here ...
},
},
]
BACKEND является пунктирным Python-путем к классу движка шаблонов, реализующему API бэкэнда шаблонов Django. Встроенные бэкэнды — django.template.backends.django.DjangoTemplates и django.template.backends.jinja2.Jinja2.
Поскольку большинство движков загружают шаблоны из файлов, верхнеуровневая конфигурация каждого движка содержит две общие настройки:
-
DIRSопределяет список каталогов, где движок должен искать исходные файлы шаблонов в порядке поиска. -
APP_DIRSуказывает, должен ли движок искать шаблоны внутри установленных приложений. Каждый бэкэнд определяет условное имя подкаталога внутри приложений, где должны храниться его шаблоны.
Хотя это нечасто требуется, можно настроить несколько экземпляров одного и того же бэкэнда с различными параметрами. В этом случае вы должны определить уникальное NAME для каждого движка.
OPTIONS содержит настройки, специфичные для бэкэнда.
Использование
Модуль django.template.loader определяет две функции для загрузки шаблонов.
-
get_template(template_name, using=None) -
Эта функция загружает шаблон с заданным именем и возвращает объект
Template.Точный тип возвращаемого значения зависит от бэкэнда, который загрузил шаблон. Каждый бэкэнд имеет свой собственный класс
Template.get_template()перебирает каждый движок шаблонов в порядке, пока один из них не найдет шаблон. Если шаблон не найден, он вызываетTemplateDoesNotExist. Если шаблон найден, но содержит неверный синтаксис, он вызываетTemplateSyntaxError.Как ищутся и загружаются шаблоны, зависит от бэкэнда и конфигурации каждого движка.
Если вы хотите ограничить поиск определенным движком шаблонов, передайте имя бэкэнда
NAMEв аргументеusing.
-
select_template(template_name_list, using=None) -
select_template()аналогичноget_template(), за исключением того, что она принимает список имен шаблонов. Она пытается найти каждый из шаблонов в порядке и возвращает первый существующий шаблон.
Если загрузка шаблона завершается ошибкой, могут быть вызваны следующие два исключения, определённые в django.template:
-
exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None) -
Это исключение возникает, когда шаблон не найден. Оно принимает следующие необязательные аргументы для заполнения отчета о шаблоне на странице отладки:
-
backend - Экземпляр бэкэнда шаблона, из которого произошло исключение.
-
tried - Список источников, которые были проверены при поиске шаблона. Он представлен в виде списка кортежей, содержащих
(origin, status), гдеorigin— объект типа origin, аstatus— строка с причиной, по которой шаблон не был найден. -
chain - Список промежуточных исключений
TemplateDoesNotExist, возникающих при попытке загрузки шаблона. Он используется функциями, такими какget_template(), которые пытаются загрузить заданный шаблон из нескольких движков.
-
-
exception TemplateSyntaxError(msg) -
Это исключение возникает, когда шаблон был найден, но содержит ошибки.
Объекты Template , возвращаемые get_template() и select_template() , должны предоставлять метод render() со следующей сигнатурой:
-
Template.render(context=None, request=None) -
Отображает этот шаблон с заданным контекстом.
Если
contextпредоставлен, он должен бытьdict. Если он не предоставлен, движок отобразит шаблон с пустым контекстом.Если
requestпредоставлен, он должен бытьHttpRequest. Тогда движок должен сделать его, а также токен CSRF, доступными в шаблоне. Как это достигается, зависит от каждого бэкэнда.
Вот пример алгоритма поиска. Для этого примера настройка TEMPLATES имеет вид:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
"/home/html/example.com",
"/home/html/default",
],
},
{
"BACKEND": "django.template.backends.jinja2.Jinja2",
"DIRS": [
"/home/html/jinja2",
],
},
]
Если вы вызовете get_template('story_detail.html'), вот какие файлы Django будет искать в порядке:
-
/home/html/example.com/story_detail.html('django'движок) -
/home/html/default/story_detail.html('django'движок) -
/home/html/jinja2/story_detail.html('jinja2'движок)
Если вы вызовете select_template(['story_253_detail.html', 'story_detail.html']), вот что Django будет искать:
-
/home/html/example.com/story_253_detail.html('django'движок) -
/home/html/default/story_253_detail.html('django'движок) -
/home/html/jinja2/story_253_detail.html('jinja2'движок) -
/home/html/example.com/story_detail.html('django'движок) -
/home/html/default/story_detail.html('django'движок) -
/home/html/jinja2/story_detail.html('jinja2'движок)
Когда Django находит существующий шаблон, он прекращает поиск.
Используйте django.template.loader.select_template() для большей гибкости
Вы можете использовать select_template() для гибкой загрузки шаблонов. Например, если вы написали новостную статью и хотите, чтобы некоторые статьи имели пользовательские шаблоны, используйте что-то вроде select_template(['story_%s_detail.html' % story.id,
'story_detail.html']). Это позволит вам использовать пользовательский шаблон для отдельной статьи со стандартным шаблоном для статей, у которых нет пользовательских шаблонов.
Возможна и предпочтительна организация шаблонов в подкаталогах внутри каждого каталога, содержащего шаблоны. Принято создавать подкаталог для каждого приложения Django с подкаталогами внутри этих подкаталогов по мере необходимости.
Сделайте это для собственного удобства. Хранение всех шаблонов в корневом уровне одного каталога неудобно.
Для загрузки шаблона, находящегося в подкаталоге, используйте обратный слэш, как показано ниже:
get_template("news/story_detail.html")
Используя тот же параметр TEMPLATES, что и выше, это будет пытаться загрузить следующие шаблоны:
-
/home/html/example.com/news/story_detail.html('django'движок) -
/home/html/default/news/story_detail.html('django'движок) -
/home/html/jinja2/news/story_detail.html('jinja2'движок)
Кроме того, для сокращения повторяющихся действий по загрузке и отображению шаблонов Django предоставляет функцию-короткую запись, которая автоматизирует этот процесс.
-
render_to_string(template_name, context=None, request=None, using=None) -
render_to_string()загружает шаблон, какget_template(), и сразу вызывает его методrender(). Она принимает следующие аргументы.-
template_name - Имя шаблона для загрузки и отображения. Если это список имён шаблонов, Django использует
select_template()вместоget_template()для поиска шаблона. -
context dictдля использования в качестве контекста шаблона при отображении.-
request - Необязательный
HttpRequest, который будет доступен во время процесса отображения шаблона. -
using - Необязательное имя движка шаблонов
NAME. Поиск шаблона будет ограничен этим движком.
Пример использования:
from django.template.loader import render_to_string rendered = render_to_string("my_template.html", {"foo": "bar"}) -
См. также render() — сокращенную функцию, которая вызывает render_to_string() и передаёт результат в HttpResponse для возврата из представления.
И наконец, вы можете напрямую использовать настроенные движки:
-
engines -
Шаблонные движки доступны в
django.template.engines:from django.template import engines django_engine = engines["django"] template = django_engine.from_string("Hello {{ name }}!")Ключ поиска —
'django'в этом примере — этоNAMEдвижка.
Встроенные бэкенды
-
class DjangoTemplates
Установите BACKEND на 'django.template.backends.django.DjangoTemplates' для настройки движка шаблонов Django.
Когда APP_DIRS равно True, движки DjangoTemplates ищут шаблоны в подкаталоге templates установленных приложений. Это общее имя сохранено для обратной совместимости.
Движки DjangoTemplates принимают следующие OPTIONS:
-
'autoescape': логическое значение, определяющее включен ли автоматический вывод HTML.По умолчанию
True.Предупреждение
Устанавливайте его только в
Falseесли вы рендерите не HTML-шаблоны! -
'context_processors': список ссылок на функции Python, используемые для заполнения контекста при рендеринге шаблона с запросом. Эти функции принимают объект запроса в качестве аргумента и возвращаютdictэлементов для объединения в контекст.По умолчанию пустой список.
См.
RequestContextдля получения дополнительной информации. -
'debug': логическое значение, включающее/выключающее отладочный режим шаблона. Если оноTrue, страница с ошибкой отобразит подробный отчёт об исключениях, возникших во время рендеринга шаблона. Отчёт содержит соответствующий фрагмент шаблона с выделенной строкой.По умолчанию принимает значение настройки
DEBUG. -
'loaders': список ссылок на классы загрузчиков шаблонов Python. Каждый классLoaderзнает, как импортировать шаблоны из определённого источника. Вместо строки можно использовать кортеж. Первый элемент кортежа должен быть именем классаLoader, а последующие элементы передаются классуLoaderпри инициализации.Значение по умолчанию зависит от значений
DIRSиAPP_DIRS.См. Типы загрузчиков для получения подробностей.
-
'string_if_invalid': вывод в виде строки, который должна использовать система шаблонов для недопустимых (например, неправильно написанных) переменных.По умолчанию пустая строка.
См. Как обрабатываются недопустимые переменные для получения подробностей.
-
'file_charset': кодировка, используемая для чтения файлов шаблонов на диске.По умолчанию
'utf-8'. -
'libraries': словарь меток и ссылок на модули тегов шаблонов Python для регистрации в движке шаблонов. Это может использоваться для добавления новых библиотек или предоставления альтернативных меток для существующих. Например:OPTIONS = { "libraries": { "myapp_tags": "path.to.myapp.tags", "admin.urls": "django.contrib.admin.templatetags.admin_urls", }, }Библиотеки могут загружаться, передавая соответствующий ключ словаря тегу
{% load %}. -
'builtins': список ссылок на модули тегов шаблонов Python для добавления в встроенные. Например:OPTIONS = { "builtins": ["myapp.builtins"], }Теги и фильтры из встроенных библиотек могут использоваться без предварительного вызова тега
{% load %}.
-
class Jinja2
Требует установленный Jinja2:
$ python -m pip install Jinja2
...\> py -m pip install Jinja2
Установите BACKEND на 'django.template.backends.jinja2.Jinja2' для настройки движка Jinja2.
Когда APP_DIRS равно True, движки Jinja2 ищут шаблоны в подкаталоге jinja2 установленных приложений.
Наиболее важный элемент в OPTIONS — 'environment'. Это ссылка на вызываемую функцию Python, возвращающую среду Jinja2. По умолчанию 'jinja2.Environment'. Django вызывает эту функцию и передаёт другие параметры в качестве ключевых аргументов. Кроме того, Django добавляет значения по умолчанию, отличающиеся от значений Jinja2 для нескольких параметров:
-
'autoescape':True -
'loader': загрузчик, настроенный дляDIRSиAPP_DIRS -
'auto_reload':settings.DEBUG -
'undefined':DebugUndefined if settings.DEBUG else Undefined
Движки Jinja2 также принимают следующие OPTIONS:
-
'context_processors': список ссылок на вызываемые функции Python, используемые для заполнения контекста при рендеринге шаблона с запросом. Эти функции принимают объект запроса в качестве аргумента и возвращаютdictэлементов для объединения в контекст.По умолчанию пустой список.
Использование процессоров контекста с шаблонами Jinja2 не рекомендуется.
Процессоры контекста полезны для шаблонов Django, потому что шаблоны Django не поддерживают вызов функций с аргументами. Поскольку Jinja2 не имеет этого ограничения, рекомендуется поместить функцию, которую вы использовали бы как процессор контекста, во глобальные переменные, доступные шаблону, как описано ниже. Затем вы можете вызвать эту функцию в шаблоне:
{{ function(request) }}Некоторые процессоры контекста Django шаблонов возвращают фиксированное значение. Для шаблонов Jinja2 такой уровень косвенности не нужен, так как вы можете добавлять константы непосредственно в
jinja2.Environment.Исходный случай использования добавления процессоров контекста для шаблонов Jinja2 включал:
- Выполнение дорогостоящего вычисления, зависящего от запроса.
- Необходимость результата во всех шаблонах.
- Использование результата несколько раз в каждом шаблоне.
Если не все эти условия соблюдены, передача функции в шаблон более соответствует дизайну Jinja2.
Конфигурация по умолчанию намеренно минимальна. Если шаблон рендерится с запросом (например, при использовании render()), бэкенд Jinja2 добавляет в контекст глобальные переменные request, csrf_input, и csrf_token. Помимо этого, этот бэкенд не создаёт среду в стиле Django. Он не знает о фильтрах и тегах Django. Чтобы использовать API Django, необходимо настроить их в среде.
Например, вы можете создать myproject/jinja2.py с этим содержимым:
from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update(
{
"static": static,
"url": reverse,
}
)
return env
и установить параметр 'environment' на 'myproject.jinja2.environment'.
Затем вы можете использовать следующие конструкции в шаблонах Jinja2:
<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">
<a href="{{ url('admin:index') }}">Administration</a>
Понятия тегов и фильтров существуют как в языке шаблонов Django, так и в Jinja2, но используются по-разному. Поскольку Jinja2 поддерживает передачу аргументов вызываемым функциям в шаблонах, многие функции, требующие тега или фильтра в шаблонах Django, могут быть реализованы вызовом функции в шаблонах Jinja2, как показано в примере выше. Глобальное пространство имён Jinja2 исключает необходимость в процессорах контекста шаблонов Django. В языке шаблонов Django нет эквивалента тестам Jinja2.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.0/topics/templates/