Шаблоны
В качестве веб-фреймворка 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. Это список конфигураций, по одному для каждого движка. Значение по умолчанию — пустое. Значение, сгенерированное командой 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— объект типа «источник» и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 находит существующий шаблон, он прекращает поиск.
Подсказка
Вы можете использовать select_template() для гибкой загрузки шаблонов. Например, если вы написали новостную историю и хотите, чтобы некоторые истории имели пользовательские шаблоны, используйте что-то вроде select_template(['story_%s_detail.html' % story.id,
'story_detail.html']). Это позволит использовать пользовательский шаблон для отдельной истории с резервным шаблоном для историй, у которых нет пользовательских шаблонов.
Возможная и предпочтительная организация шаблонов — в подкаталогах внутри каждого каталога, содержащего шаблоны. Конвенция заключается в создании подкаталога для каждого приложения Django с подкаталогами внутри этих подкаталогов по мере необходимости.
Делайте это для собственного удобства. Хранение всех шаблонов в корневом уровне одного каталога приводит к путанице.
Для загрузки шаблона, находящегося в подкаталоге, используйте слеш, как показано ниже:
get_template("news/story_detail.html")
Используя те же опции из настройка TEMPLATES, что и выше, Django попытается загрузить следующие шаблоны:
-
/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 не имеет такого ограничения, рекомендуется поместить функцию, которую вы использовали бы как процессор контекста, в глобальные переменные, доступные в шаблоне, используя
jinja2.Environment, как описано ниже. Затем вы можете вызвать эту функцию в шаблоне:{{ function(request) }}Некоторые процессоры контекста Django возвращают фиксированное значение. Для шаблонов Jinja2 этот уровень косвенности не нужен, так как вы можете добавить константы непосредственно в
jinja2.Environment.Исходный сценарий использования добавления процессоров контекста для Jinja2 включал:
- Выполнение дорогостоящих вычислений, зависящих от запроса.
- Необходимость результата во всех шаблонах.
- Использование результата несколько раз в каждом шаблоне.
Если не все эти условия соблюдаются, передача функции в шаблон лучше соответствует дизайну Jinja2.
Конфигурация по умолчанию намеренно минимизирована. Если шаблон рендерится с запросом (например, при использовании render()), Jinja2 бэкенд добавляет глобальные переменные request, csrf_input, и csrf_token в контекст. Кроме этого, этот бэкенд не создаёт среду в стиле Django. Он не знает о фильтрах и тегах Django. Для использования специфических для Django API их необходимо настроить в среде.
Например, вы можете создать 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/4.2/topics/templates/