Spec-Zone.ru › Django 6.0

Шаблоны

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

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

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

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

Шаблонизаторы настраиваются с помощью параметра 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.

Частичная загрузка:

При использовании серверной части DjangoTemplates можно загрузить именованный фрагмент шаблона. Этот фрагмент должен быть предварительно определён с помощью шаблонного тега partialdef:

from django.template.loader import get_template

# Load an entire template.
template = get_template("template.html")

# Load a specific fragment from a template.
partial = get_template("template.html#partial_name")

При загрузке частичного шаблона возвращаемый объект ведёт себя как обычный объект Template, но содержит только содержимое частичного шаблона.

Подробнее об определении и использовании фрагментов шаблонов см. в разделе Частичные шаблоны.

Изменено в Django 6.0:

Добавлена поддержка загрузки частичных шаблонов при использовании серверной части DjangoTemplates.

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 прекращает поиск.

Используйте django.template.loader.select_template() для большей гибкости

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

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 [исходный код]

Чтобы настроить шаблонизатор Django, задайте для BACKEND значение 'django.template.backends.django.DjangoTemplates'.

Если значение 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

Чтобы настроить шаблонизатор Jinja2, задайте для BACKEND значение 'django.template.backends.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 Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/topics/templates/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API