Шаблоны
Будучи веб-фреймворком, 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.
Поддержка движков шаблонов
Настройка
Движки шаблонов настраиваются с помощью параметра 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— объект типа «происхождения» иstatus— строка с причиной, по которой шаблон не был найден. -
chain - Список промежуточных исключений
TemplateDoesNotExist, возникших при попытке загрузить шаблон. Используется такими функциями, какget_template(), которые пытаются загрузить заданный шаблон из нескольких движков.
Добавлено в Django 1.9:Аргументы
backend,tried, иchainбыли добавлены. -
-
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 шаблонов!Добавлена в Django 1.10:Добавлен параметр
autoescape. -
'context_processors': список имён функций (с точкой), используемых для заполнения контекста при рендеринге шаблона с запросом. Эти функции принимают объект запроса как аргумент и возвращаютdictэлементов для объединения в контекст.По умолчанию пустой список.
См.
RequestContextдля более подробной информации. -
'debug': логическое значение, включающее/выключающее режим отладки шаблонов. Если этоTrue, то страница с ошибками отобразит подробный отчёт об исключении, возникшем при рендеринге шаблона. Этот отчёт содержит соответствующий фрагмент шаблона с выделенной строкой.По умолчанию соответствует значению настройки
DEBUG. -
'loaders': список имён классов загрузчиков шаблонов (с точкой). Каждый классLoaderзнает, как импортировать шаблоны из определённого источника. Необязательно, можно использовать кортеж вместо строки. Первый элемент кортежа должен быть именем классаLoader, а последующие элементы передаются вLoaderво время инициализации.Значение по умолчанию зависит от значений
DIRSиAPP_DIRS.См. Типы загрузчиков для деталей.
-
'string_if_invalid': результат, как строка, которую система шаблонов должна использовать для недопустимых (например, неправильно написанных) переменных.По умолчанию пустая строка.
См. Как обрабатываются недопустимые переменные для деталей.
-
'file_charset': кодировка, используемая для чтения файлов шаблонов на диске.По умолчанию соответствует значению
FILE_CHARSET. -
'libraries': словарь меток и имён (с точкой) модулей тегов шаблонов для регистрации в движке шаблонов. Это может использоваться для добавления новых библиотек или предоставления альтернативных меток для существующих. Например:OPTIONS={ 'libraries': { 'myapp_tags': 'path.to.myapp.tags', 'admin.urls': 'django.contrib.admin.templatetags.admin_urls', }, }Библиотеки могут быть загружены, передав соответствующий ключ словаря тегу
{% load %}. -
'builtins': список имён (с точкой) модулей тегов шаблонов, добавляемых в встроенные. Например:OPTIONS={ 'builtins': ['myapp.builtins'], }Теги и фильтры из встроенных библиотек могут использоваться без предварительного вызова тега
{% load %}.
Добавлены аргументы libraries и builtins.
-
class Jinja2[source]
Требуется установленный 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
Конфигурация по умолчанию намеренно минимальна. Если шаблон рендерится с запросом (например, при использовании render()), движок Jinja2 добавляет глобальные переменные request, csrf_input, и csrf_token в контекст. Помимо этого, этот движок не создаёт среду Django. Он не знает о процессорах контекста, фильтрах и тегах Django. Для использования функций Django нужно настроить их в среде.
Например, можно создать myproject/jinja2.py с таким содержимым:
from __future__ import absolute_import # Python 2 only
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'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.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(FooBar, self).__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(object):
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.
Страница отладки 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 }}
С контекстом {'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/1.10/topics/templates/