Шаблоны

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-атак и доступ к свойствам переменных шаблона, которые могут содержать конфиденциальную информацию.

Язык шаблонов 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 предоставляет множество встроенных контекстных процессоров, и вы также можете реализовать свои собственные дополнительные контекстные процессоры.

Поддержка шаблонизаторов

Конфигурация

Механизмы шаблонов настраиваются с помощью параметра 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)[исходный код]

Эта функция загружает шаблон с заданным именем и возвращает объект 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)[исходный код]

Это исключение возникает, когда не удается найти шаблон. Он принимает следующие необязательные аргументы для заполнения template postmortem на странице отладки:

backend
Экземпляр серверной части шаблона, из которого возникло исключение.
tried
Список источников, которые были опробованы при поиске шаблона. Он отформатирован как список кортежей, содержащих (origin, status), где origin - это объект origin-like, а status - строка с причиной, по которой шаблон не был найден.
chain
Список промежуточных исключений TemplateDoesNotExist, возникающих при попытке загрузить шаблон. Это используется такими функциями, как get_template(), которые пытаются загрузить данный шаблон из нескольких движков.
exception TemplateSyntaxError(msg)[исходный код]

Это исключение возникает, когда шаблон был найден, но содержит ошибки.

Объекты Template, возвращаемые get_template() и select_template(), должны предоставлять метод render() со следующей сигнатурой:

Template.render(context=None, request=None)

Отображает этот шаблон в заданном контексте.

Если указан context, он должен быть dict. Если он не указан, движок отобразит шаблон с пустым контекстом.

Если указан запрос, это должен быть 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' engine)
  • /home/html/default/story_detail.html ('django' engine)
  • /home/html/jinja2/story_detail.html ('jinja2' engine)

Если вы вызовете select_template(['story_253_detail.html', 'story_detail.html']), вот что будет искать Django:

  • /home/html/example.com/story_253_detail.html ('django' engine)
  • /home/html/default/story_253_detail.html ('django' engine)
  • /home/html/jinja2/story_253_detail.html ('jinja2' engine)
  • /home/html/example.com/story_detail.html ('django' engine)
  • /home/html/default/story_detail.html ('django' engine)
  • /home/html/jinja2/story_detail.html ('jinja2' engine)

Когда 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' engine)
  • /home/html/default/news/story_detail.html ('django' engine)
  • /home/html/jinja2/news/story_detail.html ('jinja2' engine)

Кроме того, чтобы сократить повторяющуюся природу загрузки и отрисовки шаблонов, Django предоставляет функцию быстрого доступа, которая автоматизирует процесс.

render_to_string(template_name, context=None, request=None, using=None)[исходный код]

render_to_string() загружает такой шаблон get_template(), и немедленно вызывает его метод render(). Требуются следующие аргументы.

template_name
Имя шаблона для загрузки и рендеринга. Если это список имен шаблонов, Django использует select_template() вместо get_template() для поиска шаблона.
context
dict, который будет использоваться в качестве контекста шаблона для рендеринга.
request
Необязательный HttpRequest, который будет доступен во время процесса рендеринга шаблона.
using
Необязательный шаблонизатор NAME. Поиск шаблона будет ограничен этой системой.

Пример использования:

from django.template.loader import render_to_string
rendered = render_to_string('my_template.html', {'foo': 'bar'})

Смотрите также render(), который вызывает render_to_string() и передает результат в HttpResponse, подходящий для возврата из представления.

Наконец, вы можете напрямую использовать настроенные движки:

engines

Механизмы шаблонов доступны в django.template.engines:

from django.template import engines

django_engine = engines['django']
template = django_engine.from_string("Hello {{ name }}!")

Ключ поиска - в этом примере 'django' - это параметр движка NAME.

Встроенные бэкенды

class DjangoTemplates[исходный код]

Установите BACKEND на django.template.backends.django.DjangoTemplates, чтобы настроить механизм шаблонов Django.

Когда APP_DIRS имеет значение True, движки DjangoTemplates ищут шаблоны в подкаталоге templates установленных приложений. Это общее имя было сохранено для обратной совместимости.

Механизмы DjangoTemplates принимают следующее OPTIONS:

  • autoescape: логическое значение, которое определяет, включено ли автоматическое экранирование HTML.

    По умолчанию это True.

    Предупреждение

    Установите значение False, только если вы визуализируете шаблоны, отличные от HTML!

  • context_processors“: список разделенных точками путей Python к вызываемым объектам, которые используются для заполнения контекста, когда шаблон отображается с запросом. Эти вызываемые объекты принимают объект запроса в качестве аргумента и возвращают dict элементов, которые необходимо объединить в контекст.

    По умолчанию это пустой список.

    Смотрите RequestContext для получения дополнительной информации.

  • 'debug': логическое значение, которое включает/выключает режим отладки шаблона. Если установлено значение True, на необычной странице ошибок будет отображаться подробный отчет для любых исключений, возникающих во время отрисовки шаблона. Этот отчет содержит соответствующий фрагмент шаблона с выделенной соответствующей строкой.

    По умолчанию используется значение параметра DEBUG.

  • 'loaders': список разделенных точками путей Python к классам загрузчиков шаблонов. Каждый класс Loader знает, как импортировать шаблоны из определенного источника. При желании вместо строки можно использовать кортеж. Первым элементом в кортеже должно быть имя класса Loader, а последующие элементы передаются в Loader во время инициализации.

    Значение по умолчанию зависит от значений DIRS и APP_DIRS.

    Смотрите Типы погрузчиков для подробностей.

  • 'string_if_invalid': вывод в виде строки, которую система шаблонов должна использовать для недопустимых (например, неправильно написанных) переменных.

    По умолчанию это пустая строка.

    Смотрите Как обрабатываются недопустимые переменные для подробностей.

  • 'file_charset': кодировка, используемая для чтения файлов шаблонов на диске.

    По умолчанию это 'utf-8'.

  • 'libraries': словарь меток и разделенных точками путей Python к модулям тегов шаблонов для регистрации в движке шаблонов. Это можно использовать для добавления новых библиотек или предоставления альтернативных меток для существующих. Например:

    OPTIONS={
        'libraries': {
            'myapp_tags': 'path.to.myapp.tags',
            'admin.urls': 'django.contrib.admin.templatetags.admin_urls',
        },
    }
    

    Библиотеки можно загрузить, передав соответствующий ключ словаря тегу {% load %}.

  • 'builtins': список разделенных точками путей Python к модулям тегов шаблона, которые нужно добавить в built-ins. Например:

    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 - 'nvironment'. Это пунктирный путь 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. Чтобы использовать API, специфичные для Django, вы должны настроить их в среде.

Например, вы можете создать 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.

Вернуться на верх