Шаблоны
В качестве веб-фреймворка 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 и получать доступ к свойствам переменных шаблонов, которые могут содержать конфиденциальную информацию.
Поддержка движков шаблонов
Настройка
Движки шаблонов настраиваются с помощью параметра 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)[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— объект, подобный источнику, а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': кодировка, используемая для чтения файлов шаблонов на диске.По умолчанию
'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[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 в контекст. Помимо этого, этот бэкенд не создает среду в стиле 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 не имеет эквивалента тестов 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, посмертная информация будет выглядеть так:
Настраиваемые движки могут заполнять посмертную информацию, передавая аргументы backend и tried при поднятии 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 включает четыре конструкции.
Переменные
Переменная выводит значение из контекста, который является объектом типа dict, сопоставляющим ключи со значениями.
Переменные заключены в {{ и }} следующим образом:
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 предоставляет множество встроенных обработчиков контекста. Реализация пользовательского обработчика контекста столь же проста, как определение функции.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/topics/templates/