Язык шаблонов Django: для Python программистов

This document explains the Django template system from a technical perspective – how it works and how to extend it. If you’re looking for reference on the language syntax, see Язык шаблонов Django.

Этот документ подразумевает, что вы уже знакомы с шаблонами, контекстом, переменными, тегами и рендерингом. Если вам не знакомы эти концепции, начните с вступления в систему шаблонов Django.

Введение

Система шаблонов в Python работает в два этапа:

  1. Вы настраиваете Engine.
  2. Сначала вы компилируете код шаблона в объект Template.
  3. Вы рендерите шаблон с Context.

Django использует высокоуровневый API, который не привязан к конкретному бэкенду:

  1. Для каждого бэкенда DjangoTemplates из настройки the TEMPLATES, Django создает экземпляр Engine. DjangoTemplates оборачивает Engine, чтобы адаптировать его под API конкретного бэкенда шаблонов.
  2. Модуль django.template.loader предоставляет функции, такие как get_template(), для загрузки шаблонов. Они возвращают django.template.backends.django.Template, который оборачивает django.template.Template.
  3. Template, полученный на предыдущем шаге, содержит метод render(), который оборачивает контекст и запрос в Context и делегирует рендеринг основному объекту Template.

Настройка бэкенда

If you are using the DjangoTemplates backend, this probably isn’t the documentation you’re looking for. An instance of the Engine class described below is accessible using the engine attribute of that backend and any attribute defaults mentioned below are overridden by what’s passed by DjangoTemplates.

class Engine(dirs=None, app_dirs=False, context_processors=None, debug=False, loaders=None, string_if_invalid='', file_charset='utf-8', libraries=None, builtins=None, autoescape=True)

При создании Engine все аргументы должны передаваться как именованные:

  • dirs – это список каталого, в которых бэкенд ищет файлы шаблонов. Используется для настройки filesystem.Loader.

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

  • app_dirs влияет только на значение loaders по умолчанию. Смотрите ниже.

    По умолчанию False.

  • autoescape controls whether HTML autoescaping is enabled.

    It defaults to True.

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

    Only set it to False if you’re rendering non-HTML templates!

  • context_processors – список путей Python для импорта функций, которые используются для наполнения контекста шаблонов, если он рендерится с объектом запроса. Эти функции принимают объект запроса и возвращают dict значений, которые будут добавлены в контекст.

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

    Подробности смотрите в описании RequestContext.

  • debug – булево значение, которое включает и выключает режим отладки. При True шаблонизатор сохраняет дополнительную отладочную информацию, которая может использоваться для отображения информации ошибки, которая возникла во время рендеринга.

    По умолчанию False.

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

    По умолчанию содержит список:

    • 'django.template.loaders.filesystem.Loader'
    • 'django.template.loaders.app_directories.Loader', только если app_dirs равен True.

    If debug is False, these loaders are wrapped in django.template.loaders.cached.Loader.

    Подробности смотрите в Типы загрузчиков.

  • string_if_invalid значение, которые шаблонизатор выведет вместо неправильной переменной(например, с опечаткой в назчании).

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

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

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

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

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

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

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

  • 'builtins': Список путей Python к модулям с тегами, которые будут добавлены к встроенным. Например:

    Engine(
        builtins=['myapp.builtins'],
    )
    

    Теги и фильтры из этих модулей можно использовать без вызова тега {% load %}.

static Engine.get_default()

Returns the underlying Engine from the first configured DjangoTemplates engine. Raises ImproperlyConfigured if no engines are configured.

Необходим для совместимости API, который рассчитывает на глобальный, неявно настроенный механизм шаблонов. Не следует использовать для других ситуаций.

Engine.from_string(template_code)

Сначала вы компилируете код шаблона в объект Template.

Engine.get_template(template_name)

Загружает шаблон с указанным названием, компилирует его и возвращает объект Template.

Engine.select_template(template_name_list)

Похож на get_template(), но принимает список шаблонов и возвращает первый доступный шаблон из списка.

Загрузка шаблонов

Рекомендуемый метод создать Template – использовать методы-фабрики Engine: get_template(), select_template() и from_string().

In a Django project where the TEMPLATES setting defines a DjangoTemplates engine, it’s possible to instantiate a Template directly. If more than one DjangoTemplates engine is defined, the first one will be used.

class Template

Класс находится в django.template.Template. Конструктор принимает один аргумент – «сырой» код шаблона:

from django.template import Template

template = Template("My name is {{ my_name }}.")

За кулисами

Система парсит код шаблона один раз – когда вы создаете объект Template. Результат для оптимизации сохраняется в памяти как древовидная структура.

Сам по себе парсинг работает достаточно быстро, обычно с помощью небольших регулярных выражений.

Рендеринг контекста

Скомпилировав объект Template, вы можете отрендерить с его помощью контекст. Вы можете использовать один и тот же объект шаблона, чтобы отрендерить несколько контекстов.

class Context(dict_=None)

The constructor of django.template.Context takes an optional argument — a dictionary mapping variable names to variable values.

Подробности смотрте ниже в Playing with Context objects.

Template.render(context)

Вызовите метод render() объекта Template с контекстом, чтобы «выполнить» шаблон:

>>> from django.template import Context, Template
>>> template = Template("My name is {{ my_name }}.")

>>> context = Context({"my_name": "Adrian"})
>>> template.render(context)
"My name is Adrian."

>>> context = Context({"my_name": "Dolores"})
>>> template.render(context)
"My name is Dolores."

Переменные

Название переменной может состоять из букв (A-Z), цифр (0-9), подчеркивания (но не начинаться с подчеркивания) или точки.

У точки особое значение. Точка в названии переменной означает поиск. Встретив точку в названии переменной, система шаблонов пытается найти значение в следующем подряке:

  • Поиск в словаре. Например: foo["bar"]
  • Поиск атрибута. Например: foo.bar
  • Поиск в списке. Напрмиер: foo[bar]

Обратите внимание, «bar» в выражении {{ foo.bar }} будет интепретировано как строка «bar», а не переменная с названием «bar».

Система шаблонов будет использовать первое найденное значение. Вот несколько примеров:

>>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
>>> t.render(Context(d))
"My name is Joe."

>>> class PersonClass: pass
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
>>> t.render(Context({"person": p}))
"My name is Ron."

>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."

Если найдена функция, или любой другой вызываемый объект, шаблон попытается вызвать её. Например:

>>> class PersonClass2:
...     def name(self):
...         return "Samantha"
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."

Вызываемые переменные работают немного сложнее. Вам следует помнить о следующем:

  • Если выполнение функции вызвало исключение, это приведет к ошибке при выполнении шаблона, если только исключение не содержит атрибут silent_variable_failure равный True. В таком случае переменная будет отрендерена со значением опции string_if_invalid шаблонизатора (пустая строка по умолчанию). Например:

    >>> t = Template("My name is {{ person.first_name }}.")
    >>> class PersonClass3:
    ...     def first_name(self):
    ...         raise AssertionError("foo")
    >>> p = PersonClass3()
    >>> t.render(Context({"person": p}))
    Traceback (most recent call last):
    ...
    AssertionError: foo
    
    >>> class SilentAssertionError(Exception):
    ...     silent_variable_failure = True
    >>> class PersonClass4:
    ...     def first_name(self):
    ...         raise SilentAssertionError
    >>> p = PersonClass4()
    >>> t.render(Context({"person": p}))
    "My name is ."
    

    Обратите внимание, django.core.exceptions.ObjectDoesNotExist, который является родительским для всех ошибок DoesNotExist в ORM, содержит silent_variable_failure = True. Поэтому, если вы используете объекты модели в шаблонах, исключение DoesNotExist будет проигнорировано.

  • Функция из переменной может быть вызвана, только если не требует обязательных аргументов. В таком случае шаблон вставит вместо переменной значение string_if_invalid.

  • There can be side effects when calling some variables, and it’d be either foolish or a security hole to allow the template system to access them.

    Хороший пример – метод delete() модели. Нельзя позволять шаблонам выполнять следующее:

    I will now delete this valuable data. {{ data.delete }}
    

    Чтобы избежать этого, укажите атрибут alters_data в функции или методе. Шаблон не будет вызывать переменную, если значение содержит alters_data=True, и будет использовать значение настройки string_if_invalid. Встроенные методы delete() и save() модели содержат атрибут alters_data=True. Например:

    def sensitive_function(self):
        self.database_record.delete()
    sensitive_function.alters_data = True
    
  • В некоторых случая может понадобится отключить вызов переменной и использовать значение как есть. Для этого укажите атрибут do_not_call_in_templates со значением True. Шаблон будет интерпретировать такую функцию как не вызываемое значение (позволяя обратиться к её атрибутам, например).

Как обрабатываются неправильные переменные

Если переменная не найдена в шаблоне, будет использоваться значение опции string_if_invalid шаблонизатора, равной по умолчанию '' (пустая строка).

Фильтры, которые указаны для переменной, будут применяться, только если string_if_invalid равна '' (пустая строка). Если string_if_invalid равна другому значению, фильтры будут проигнорированы.

Теги if, for и regroup работают немного по другому. Если указать неправильную переменную, будет использоваться значение None. Фильтры всегда применяются к переменной в этих тегах.

Если string_if_invalid содержит '%s', будет подставлено название переменной.

Только для отладки!

Хотя string_if_invalid и полезная для отладки, лучше не менять её по умолчанию и использовать только при необходимости локально.

Many templates, including some of Django’s, rely upon the silence of the template system when a nonexistent variable is encountered. If you assign a value other than '' to string_if_invalid, you will experience rendering problems with these templates and sites.

Как правило string_if_invalid необходимо использовать для отладки конкретной проблемы в шаблоне, и после отладки возвращать значение по умолчанию.

Встроенные переменные

Каждый контекст содержит True, False и None. Как и следовало ожидать эти переменные соответствуют объектам Python.

Ограничения текстовых литералов

Система шаблонов Django не позволяет экранировать символы, которые используются в синтаксисе разметки шаблонов. Например, следует использовать тег templatetag, если необходимо вывести в шаблоне {% и %} как строки.

Аналогичные проблемы возникают, если необходимо использовать эти значения как аргумент фильтра или тега. Например, при парсинге блочного тега, Django ищет первое появление %} после {%. Таким образом нельзя использовать "%}" как текст. Например, в следующих ситуациях будет вызвано исключение TemplateSyntaxError:

{% include "template.html" tvar="Some string literal with %} in it." %}

{% with tvar="Some string literal with %} in it." %}{% endwith %}

Аналогичная проблема возникнет при использовании }} в качестве аргумента фильтра:

{{ some.variable|default:"}}" }}

Чтобы обойти эти ограничения, используйте переменную для хранения запрещенных строк, или свой теги или фильтр, чтобы обойти ограничения.

Playing with Context objects

Обычно при создании объекта Context сразу передается словарь со всеми переменными. Но вы можете менять содержимое объекта Context и после его инициализации, использую стандартный API словарей:

>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'
Context.get(key, otherwise=None)

Возвращает значение для key, если key находится в контексте, иначе возвращает otherwise.

Context.setdefault(key, default=None)

Если контекст содержит key, вернет его значение. Иначе добавит key с значением default и вернет default.

Context.pop()
Context.push()
exception ContextPopException

Объект Context работает как стек. Поэтому можно использовать методы push() и pop(). Если вызывать pop() слишком часто, будет вызвано исключение django.template.ContextPopException:

>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.push()
{}
>>> c['foo'] = 'second level'
>>> c['foo']
'second level'
>>> c.pop()
{'foo': 'second level'}
>>> c['foo']
'first level'
>>> c['foo'] = 'overwritten'
>>> c['foo']
'overwritten'
>>> c.pop()
Traceback (most recent call last):
...
ContextPopException

push() можно использовать как менеджер контекста, чтобы быть уверенным, что будет pop() вызван в конце.

>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push():
...     c['foo'] = 'second level'
...     c['foo']
'second level'
>>> c['foo']
'first level'

Все аргументы push() будут переданы в конструктор dict при создании нового слоя в контексте.

>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push(foo='second level'):
...     c['foo']
'second level'
>>> c['foo']
'first level'
Context.update(other_dict)

Кроме push() и pop() объект Context также предоставляет метод update(). Работает как и push(), но принимает словарь в качестве аргумента и добавляет его в стек.

>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'foo': 'updated'})
{'foo': 'updated'}
>>> c['foo']
'updated'
>>> c.pop()
{'foo': 'updated'}
>>> c['foo']
'first level'

Как и push(), вы можете использовать update() как менеджер контекста, чтобы быть уверенным, что будет pop() вызван в конце.

>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.update({'foo': 'second level'}):
...     c['foo']
'second level'
>>> c['foo']
'first level'

Использовать Context, как стек, удобно в собственных тегах..

Context.flatten()

Метод flatten() возвращает весь стек Context одним словарём, включая встроенные переменные.

>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'bar': 'second level'})
{'bar': 'second level'}
>>> c.flatten()
{'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}

Метод flatten() также используется для сравнения объектов Context внутри системы шаблонов.

>>> c1 = Context()
>>> c1['foo'] = 'first level'
>>> c1['bar'] = 'second level'
>>> c2 = Context()
>>> c2.update({'bar': 'second level', 'foo': 'first level'})
{'foo': 'first level', 'bar': 'second level'}
>>> c1 == c2
True

Результат flatten() можно использовать в тестах для сравнения Context и dict:

class ContextTest(unittest.TestCase):
    def test_against_dictionary(self):
        c1 = Context()
        c1['update'] = 'value'
        self.assertEqual(c1.flatten(), {
            'True': True,
            'None': None,
            'False': False,
            'update': 'value',
        })

Using RequestContext

class RequestContext(request, dict_=None, processors=None)

Django предоставляет специальный класс Context, django.template.RequestContext, который немного отличается от обычного django.template.Context. Первое отличие – он принимает HttpRequest первым аргументом. Например:

c = RequestContext(request, {
    'foo': 'bar',
})

Еще одно отличие – он автоматически добавляет различные переменные в соответствии с опцией context_processors шаблонизатора.

context_processors содержит кортеж функций, которые называются процессорами контекста. Они принимают объект запроса в качестве аргумента и возвращают словарь переменных, которые будут добавлены в контекст. По умолчанию context_processors равна:

[
    'django.template.context_processors.debug',
    'django.template.context_processors.request',
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
]

Кроме этого RequestContext всегда использует django.core.context_processors.csrf. Этот процессор контекста используется для безопасности админкой и другими встроенными приложениями. Чтобы исключить его случайное отключение, он захардкоден и не может быть выключен с помощью настройки context_processors.

Процессоры контекста применяются по очереди. Это означает, что один процессор может перетереть переменную, которую добавил предыдущий. Процессоры по умолчанию описаны ниже.

Когда применяются процессоры контекста

Процессоры контекста применяются после инициализации контекста. То есть процессор может перезаписать переменную, которую вы добавили в Context или RequestContext. Поэтому избегайте названий переменных, которые используются процессорами.

Если вы хотите, чтобы переменная контекста перезаписывала переменные процессора контекста, используйте следующий подход:

from django.template import RequestContext

request_context = RequestContext(request)
request_context.push({"my_name": "Adrian"})

Django использует такой способ, чтобы перезаписать процессоры контекста во внутреннем API, например render() и TemplateResponse.

Also, you can give RequestContext a list of additional processors, using the optional, third positional argument, processors. In this example, the RequestContext instance gets an ip_address variable:

from django.http import HttpResponse
from django.template import RequestContext, Template

def ip_address_processor(request):
    return {'ip_address': request.META['REMOTE_ADDR']}

def client_ip_view(request):
    template = Template('{{ title }}: {{ ip_address }}')
    context = RequestContext(request, {
        'title': 'Your IP Address',
    }, [ip_address_processor])
    return HttpResponse(template.render(context))

Встроенные процессоры контекста

Вот список процессоров контекста по умолчанию:

django.contrib.auth.context_processors.auth

auth()

Если включить этот процессор, в RequestContext будут добавлены следующие переменные:

  • user – объект auth.User текущего авторизованного пользователя или объект AnonymousUser, если пользователь не авторизованный).
  • perms – объект django.contrib.auth.context_processors.PermWrapper, которые содержит права доступа текущего пользователя.

django.template.context_processors.debug

debug()

Если включить этот процессор, в RequestContext будут добавлены следующие переменные, но только при DEBUG равном True и, если IP адрес запроса (request.META['REMOTE_ADDR']) указан в INTERNAL_IPS:

  • debugTrue. Вы можете использовать эту переменную, чтобы определить DEBUG режим в шаблоне.
  • sql_queries – A list of {'sql': ..., 'time': ...} dictionaries, representing every SQL query that has happened so far during the request and how long it took. The list is in order by database alias and then by query. It’s lazily generated on access.

django.template.context_processors.i18n

i18n()

Если включить этот процессор, в RequestContext будут добавлены следующие переменные:

  • LANGUAGES – значение настройки LANGUAGES.
  • LANGUAGE_BIDITrue if the current language is a right-to-left language, e.g. Hebrew, Arabic. False if it’s a left-to-right language, e.g. English, French, German.
  • LANGUAGE_CODErequest.LANGUAGE_CODE, если существует. Иначе значение LANGUAGE_CODE.

See i18n template tags for template tags that generate the same values.

django.template.context_processors.media

Если включить этот процессор, в RequestContext будет добавлена переменная MEDIA_URL, которая содержит значение MEDIA_URL.

django.template.context_processors.static

static()

Если включить этот процессор, в RequestContext будет добавлена переменная STATIC_URL, которая содержит значение STATIC_URL.

django.template.context_processors.csrf

Этот процессор добавляет токен, который используется тегом csrf_token для защиты от CSRF атак.

django.template.context_processors.request

Если включить этот процессор, в RequestContext будет добавлена переменная request, содержащая текущий HttpRequest.

django.template.context_processors.tz

tz()

If this processor is enabled, every RequestContext will contain a variable TIME_ZONE, providing the name of the currently active time zone.

django.contrib.messages.context_processors.messages

Если включить этот процессор, в RequestContext будут добавлены следующие переменные:

Как создать свой процессор контекста

A context processor has a simple interface: It’s a Python function that takes one argument, an HttpRequest object, and returns a dictionary that gets added to the template context. Each context processor must return a dictionary.

Код процессора может находится где угодно. Главное не забыть указать его в опции 'context_processors' настройки:setting:TEMPLATES, или передать аргументом context_processors в Engine.

Загрузка шаблонов

Обычно при разработке проекта шаблоны хранятся в файлах, а не создаются с помощью API Template. Сохраняйте их в каталоге, который называют каталог с шаблонами.

Django ищет каталоги с шаблонами в соответствии с настройками загрузки шаблонов (смотрите «Типа загрузчиков» ниже). Самый простой способ – указать каталоги с шаблонами в опции DIRS.

Опция DIRS

Вы можете указать Django каталоги с шаблонами через опцию DIRS настройки TEMPLATES, или в аргументе dirs при создании Engine. Настройка должна содержать список или кортеж полных путей к каталогам. Например:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            '/home/html/templates/lawrence.com',
            '/home/html/templates/default',
        ],
    },
]

Шаблоны могут находиться где угодно, главное, чтобы у Web-сервера были права на чтение. Расширение файла может быть любым, .html или .txt, или вообще без расширения.

Обратите внимание, пути должны быть Unix-стиле, даже для Windows (то есть использовать /).

Типы загрузчиков

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

Некоторые из них выключены по умолчанию, но вы можете активировать их изменив опцию 'loaders' бэкенда DjangoTemplates в настройке TEMPLATES, или передав аргумент loaders в Engine. Опция loaders содержит кортеж строк, каждая из которых представляет класс загрузчика шаблонов. Вот список загрузчиков, которые предоставляет Django:

django.template.loaders.filesystem.Loader

class filesystem.Loader

Загружает шаблоны с файловой системы в соответствии с настройкой DIRS.

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

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, 'templates')],
}]

You can also override 'DIRS' and specify specific directories for a particular filesystem loader:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'OPTIONS': {
        'loaders': [
            (
                'django.template.loaders.filesystem.Loader',
                [os.path.join(BASE_DIR, 'templates')],
            ),
        ],
    },
}]

django.template.loaders.app_directories.Loader

class app_directories.Loader

Загружает шаблоны из каталога приложения Django. Для каждого приложения в INSTALLED_APPS загрузчик ищет под-каталог templates. Если под-каталог найден, Django ищет в нем шаблон.

This means you can store templates with your individual apps. This also helps to distribute Django apps with default templates.

Например для следующих настроек:

INSTALLED_APPS = ['myproject.polls', 'myproject.music']

get_template('foo.html') будет искать foo.html в таких каталогах в указанном порядке:

  • /path/to/myproject/polls/templates/
  • /path/to/myproject/music/templates/

… и будет использовать первый найденный.

Порядок INSTALLED_APPS – важен! Например, вы хотите переопределить шаблон админки Django, например admin/base_site.html из django.contrib.admin, заменив на admin/base_site.html из myproject.polls. Вы должны указать myproject.polls перед django.contrib.admin в INSTALLED_APPS, иначе шаблон из django.contrib.admin будет загружен первым, а ваш проигнорирован.

Обратите внимание, загрузчик выполняет некоторую оптимизацию при первом импорте: он кеширует список приложений из INSTALLED_APPS, которые содержат под-каталог templates.

You can enable this loader by setting APP_DIRS to True:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'APP_DIRS': True,
}]

django.template.loaders.cached.Loader

class cached.Loader

By default (when DEBUG is True), the template system reads and compiles your templates every time they’re rendered. While the Django template system is quite fast, the overhead from reading and compiling templates can add up.

You configure the cached template loader with a list of other loaders that it should wrap. The wrapped loaders are used to locate unknown templates when they’re first encountered. The cached loader then stores the compiled Template in memory. The cached Template instance is returned for subsequent requests to load the same template.

This loader is automatically enabled if OPTIONS['loaders'] isn’t specified and OPTIONS['debug'] is False (the latter option defaults to the value of DEBUG).

You can also enable template caching with some custom template loaders using settings like this:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, 'templates')],
    'OPTIONS': {
        'loaders': [
            ('django.template.loaders.cached.Loader', [
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
                'path.to.custom.Loader',
            ]),
        ],
    },
}]

Примечание

Все встроенные теги Django можно использовать с кеширующим загрузчиком, но теги сторонних приложений, или ваши собственные, должны использовать потокобезопасный код при использовании класса Node. Смотрите Потокобезопасные шаблонные теги.

django.template.loaders.locmem.Loader

class locmem.Loader

Загружает шаблоны из словаря Python. Удобен при тестировании.

Этот загрузчик принимает словарь каталогов первым аргументом:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'OPTIONS': {
        'loaders': [
            ('django.template.loaders.locmem.Loader', {
                'index.html': 'content here',
            }),
        ],
    },
}]

Загрузчик выключен по умолчанию.

Django использует загрузчики шаблонов в порядке, указанном в опции 'loaders'. Загрузчики используются пока один из них не найдет шаблон.

Собственные загрузчики

Вы можете загружать шаблоны из дополнительных источников, используя собственный загрузчик шаблонов. Собственный класс Loader должен наследоваться от django.template.loaders.base.Loader и определять методы get_contents() и get_template_sources().

Методы загрузчика шаблонов

class Loader

Загружает шаблоны из определенного источника, такого как файловая система или база данных.

get_template_sources(template_name)

Метод принимает template_name и возвращает итератора по экземплярам Origin для каждого возможного источника шаблонов.

Например, загрузчик с файловой системы получает 'index.html' в аргументе template_name. Этот метод вернет итератор, который содержит полные пути к index.html для каждого каталога, в котором он выполняет поиск шаблонов.

Этот метод не проверяет находится ли шаблон по указанному пути, но путь должен быть правильным. Например, загрузчик с файловой системы проверяет, что путь находится в каталоге с шаблонами.

get_contents(origin)

Возвращает содержимое шаблона для переданного экземпляра Origin.

В этом методе загрузчик прочитает содержимое с файловой системы, или базы данных. Если шаблон не найден, метод должен вызвать исключение TemplateDoesNotExist.

get_template(template_name, skip=None)

Возвращает объект Template для переданного template_name, проверяя все источники из get_template_sources() и вызывая get_contents(). Возвращает первый найденный шаблон. Если шаблон не найден, будет вызвано исключение TemplateDoesNotExist.

Необязательный аргумент skip содержит список источников, которые игнорируются при наследовании шаблонов. Это позволяет шаблонам наследовать шаблоны с одинаковыми именами. Также позволяет избежать ошибки о рекурсии.

Обычно достаточно определить методы get_template_sources() и get_contents(). get_template() обычно не нужно переопределять.

Создание собственного загрузчика

For examples, read the source code for Django’s built-in loaders.

Расположение шаблона

Шаблоны содержат атрибут origin, поля которого зависят от загрузчика шаблона.

class Origin(name, template_name=None, loader=None)
name

Путь к шаблону, который вернул загрузчик шаблонов. Для загрузчиков, которые ищут в файловой системе, это будет полный путь к файлу шаблона.

Если шаблон создан на прямую, без загрузчика шаблонов, это поле содержит <unknown_source>.

template_name

Относительный путь к шаблону, которые передается в загрузчик шаблонов.

Если шаблон создан на прямую, без загрузчика шаблонов, это поле содержит None.

loader

The template loader instance that constructed this Origin.

Если шаблон создан на прямую, без загрузчика шаблонов, это поле содержит None.

django.template.loaders.cached.Loader requires all of its wrapped loaders to set this attribute, typically by instantiating the Origin with loader=self.