Шаблоны
В качестве веб-фреймворка, Django нуждается в удобном способе динамической генерации HTML. Наиболее распространённый подход основан на шаблонах. Шаблон содержит статические части желаемого HTML-вывода, а также специальный синтаксис, описывающий, как будет вставляться динамическое содержимое. Для практического примера создания HTML-страниц с помощью шаблонов см. Урок 3.
Проект Django может быть настроен с одним или несколькими движками шаблонов (или даже нулевым, если вы не используете шаблоны). Django поставляется со встроенными бэкендами для собственной системы шаблонов, креативно названной языком шаблонов Django (DTL), и для популярной альтернативы Jinja2. Бэкенды для других языков шаблонов могут быть доступны от сторонних разработчиков.
Django определяет стандартный API для загрузки и рендеринга шаблонов независимо от бэкенда. Загрузка заключается в поиске шаблона по заданному идентификатору и его предварительной обработке, обычно компиляции в представление в памяти. Рендеринг означает интерполяцию шаблона с данными контекста и возвращение результирующей строки.
Язык шаблонов Django — собственная система шаблонов Django. До Django 1.8 он был единственным доступным встроенным вариантом. Это хорошая библиотека шаблонов, хотя она довольно категоричная и имеет несколько особенностей. Если у вас нет веских причин выбрать другой бэкенд, вы должны использовать DTL, особенно если вы пишете подключаемый модуль и планируете распространять шаблоны. Приложения contrib Django, включающие шаблоны, такие как django.contrib.admin, используют DTL.
По историческим причинам, как общая поддержка движков шаблонов, так и реализация языка шаблонов Django находятся в пространстве имен django.template.
Предупреждение
Система шаблонов не защищена от ненадёжных авторов шаблонов. Например, сайт не должен разрешать пользователям предоставлять собственные шаблоны, так как авторы шаблонов могут выполнять такие действия, как атаки XSS и доступ к свойствам переменных шаблонов, которые могут содержать конфиденциальную информацию.
Поддержка движков шаблонов
Настройка
Движки шаблонов настраиваются с помощью настройки 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)[source] -
Эта функция загружает шаблон с данным именем и возвращает объект
Template.Точный тип возвращаемого значения зависит от бэкенда, который загрузил шаблон. Каждый бэкенд имеет свой собственный класс
Template.get_template()перебирает каждый движок шаблонов в порядке, пока один из них не выполнит поиск. Если шаблон не найден, он вызываетTemplateDoesNotExist. Если шаблон найден, но содержит недопустимый синтаксис, он вызываетTemplateSyntaxError.Как ищутся и загружаются шаблоны, зависит от бэкенда каждого движка и конфигурации.
Если вы хотите ограничить поиск определённым движком шаблонов, передайте имя бэкенда
NAMEв аргументеusing.
-
select_template(template_name_list, using=None)[source] -
select_template()аналогичноget_template(), за исключением того, что она принимает список имён шаблонов. Она пытается найти каждое имя в порядке и возвращает первый найденный шаблон.
Если загрузка шаблона завершается ошибкой, могут быть вызваны следующие две исключения, определённые в django.template.
-
exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)[source] -
Это исключение возникает, когда шаблон не найден. Оно принимает следующие необязательные аргументы для заполнения отчёта о шаблоне на странице отладки:
-
backend - Экземпляр бэкенда шаблонов, от которого возникло исключение.
-
tried - Список источников, которые были проверены при поиске шаблона. Это отформатирован как список кортежей, содержащих
(origin, status), гдеorigin— это объект типа origin-like, аstatus— строка с причиной, по которой шаблон не был найден. -
chain - Список промежуточных исключений
TemplateDoesNotExist, возникших при попытке загрузки шаблона. Это используется функциями, такими какget_template(), которые пытаются загрузить указанный шаблон из нескольких движков.
-
-
exception TemplateSyntaxError(msg)[source] -
Это исключение возникает, когда шаблон был найден, но содержит ошибки.
Объекты 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, что и выше, это будет пытаться загрузить следующие шаблоны:
-
/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)[source] -
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[source]
Установите 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': кодировка, используемая для чтения файлов шаблонов на диске.По умолчанию значение настройки
FILE_CHARSET. -
'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[source]
Требуется установка Jinja2:
$ pip install Jinja2
...\> 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. Помимо этого, этот бэкэнд не создаёт среду с джанго-специфичными настройками. Он не знает о джанго-фильтрах и тегах. Для использования джанго-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 нет аналога тестов Jinja2.
Настраиваемые бэкэнды
Вот как реализовать настраиваемый бэкэнд шаблонов, чтобы использовать другую систему шаблонов. Бэкэнд шаблона — это класс, который наследует django.template.backends.base.BaseEngine. Он должен реализовывать get_template() и необязательно from_string(). Вот пример для вымышленной библиотеки шаблонов foobar:
from django.template import TemplateDoesNotExist, TemplateSyntaxError
from django.template.backends.base import BaseEngine
from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
import foobar
class FooBar(BaseEngine):
# Name of the subdirectory containing the templates for this engine
# inside an installed application.
app_dirname = 'foobar'
def __init__(self, params):
params = params.copy()
options = params.pop('OPTIONS').copy()
super().__init__(params)
self.engine = foobar.Engine(**options)
def from_string(self, template_code):
try:
return Template(self.engine.from_string(template_code))
except foobar.TemplateCompilationFailed as exc:
raise TemplateSyntaxError(exc.args)
def get_template(self, template_name):
try:
return Template(self.engine.get_template(template_name))
except foobar.TemplateNotFound as exc:
raise TemplateDoesNotExist(exc.args, backend=self)
except foobar.TemplateCompilationFailed as exc:
raise TemplateSyntaxError(exc.args)
class Template:
def __init__(self, template):
self.template = template
def render(self, context=None, request=None):
if context is None:
context = {}
if request is not None:
context['request'] = request
context['csrf_input'] = csrf_input_lazy(request)
context['csrf_token'] = csrf_token_lazy(request)
return self.template.render(context)
Дополнительную информацию см. в DEP 182.
Интеграция отладки для настраиваемых движков
Страница отладки Django имеет крючки для предоставления подробной информации при возникновении ошибки шаблона. Настраиваемые движки шаблонов могут использовать эти крючки для улучшения информации об отслеживании ошибок, которая отображается пользователям. Доступны следующие крючки:
Постмортём шаблона
Постмортём появляется при возникновении TemplateDoesNotExist. Он перечисляет движки и загрузчики шаблонов, которые использовались при попытке найти заданный шаблон. Например, если настроены два движка Django, постмортём будет выглядеть следующим образом:
TemplateDoesNotExist. Бэкэнды, использующие сведения о завершении работы, должны указать происхождение в объекте шаблона.Информация о контекстных строках
Если при разборе или рендеринге шаблона произойдёт ошибка, Django может отобразить строку, на которой произошла ошибка. Например:
Пользовательские движки могут заполнить эту информацию, установив атрибут template_debug для исключений, возникающих во время разбора и рендеринга. Этот атрибут — dict со следующими значениями:
-
'name': Имя шаблона, в котором произошла ошибка. -
'message': Сообщение об ошибке. -
'source_lines': Строки перед, после и включая строку, на которой произошла ошибка. Это необходимо для контекста, поэтому он не должен содержать более 20 строк. -
'line': Номер строки, на которой произошла ошибка. -
'before': Содержимое строки с ошибкой до токена, вызвавшего ошибку. -
'during': Токен, вызвавший ошибку. -
'after': Содержимое строки с ошибкой после токена, вызвавшего ошибку. -
'total': Количество строк вsource_lines. -
'top': Номер строки, где начинаетсяsource_lines. -
'bottom': Номер строки, где заканчиваетсяsource_lines.
Учитывая ошибку шаблона выше, template_debug будет выглядеть так:
{
'name': '/path/to/template.html',
'message': "Invalid block tag: 'syntax'",
'source_lines': [
(1, 'some\n'),
(2, 'lines\n'),
(3, 'before\n'),
(4, 'Hello {% syntax error %} {{ world }}\n'),
(5, 'some\n'),
(6, 'lines\n'),
(7, 'after\n'),
(8, ''),
],
'line': 4,
'before': 'Hello ',
'during': '{% syntax error %}',
'after': ' {{ world }}\n',
'total': 9,
'bottom': 9,
'top': 1,
}
API происхождения и интеграция сторонних систем
Шаблоны Django имеют объект Origin, доступный через атрибут template.origin. Это позволяет отображать отладочную информацию в послесборке шаблона, а также в сторонних библиотеках, таких как Django Debug Toolbar.
Пользовательские движки могут предоставлять свою информацию template.origin путём создания объекта, который определяет следующие атрибуты:
-
'name': Полный путь к шаблону. -
'template_name': Относительный путь к шаблону, переданный в методы загрузки шаблонов. -
'loader_name': Необязательная строка, идентифицирующая функцию или класс, используемые для загрузки шаблона, например,django.template.loaders.filesystem.Loader.
Язык шаблонов 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 }}
При контексте {'first_name': 'John', 'last_name': 'Doe'}, этот шаблон отображается в:
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 предоставляет множество встроенных обработчиков контекста. Реализация пользовательского обработчика контекста так же проста, как определение функции.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.1/topics/templates/