Шаблоны
Будучи веб-фреймворком, 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. Это список настроек, по одной для каждого движка. Значение по умолчанию — пустой список. Значение, сгенерированное командой 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, что и выше, это приведет к попытке загрузки следующих шаблонов:
-
/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 предоставляет функцию-обёртку, которая автоматизирует этот процесс.
END_OF_DOCUMENT_MARKER-
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 -
settings.DEBUG: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/3.0/topics/templates/