Spec-Zone.ru › Django 4.2

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

В этом документе язык Django шаблонов объясняется с технической точки зрения — как он работает и как его расширить. Если вы ищете справочник по синтаксису языка, см. Язык шаблонов Django.

Предполагается понимание шаблонов, контекстов, переменных, тегов и рендеринга. Начните с введения в язык шаблонов Django, если вы не знакомы с этими понятиями.

Обзор

Использование системы шаблонов на Python — это трехэтапный процесс:

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

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

  1. Для каждого DjangoTemplates бэкенда в настройке 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.

Настройка движка

Если вы используете бэкенд DjangoTemplates, это, вероятно, не тот документ, который вы ищете. Экземпляр класса Engine ниже доступен через атрибут engine этого бэкенда, и любые значения по умолчанию атрибутов, упомянутые ниже, переопределяются переданными значениями через 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 управляет включением автоэскейпинга HTML.

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

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

    Установите его в False только если вы рендерите не HTML-шаблоны!

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

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

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

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

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

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

    По умолчанию — список, содержащий:

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

    Эти загрузчики затем оборачиваются в django.template.loaders.cached.Loader.

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

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

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

  • 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()

Возвращает базовый Engine из первого настроенного DjangoTemplates движка. Вызывает ImproperlyConfigured, если движки не настроены.

Необходимо для сохранения 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().

END_OF_DOCUMENT_MARKER ```

В проекте Django, где настройка TEMPLATES определяет движок DjangoTemplates, можно напрямую создать объект Template. Если определено более одного движка DjangoTemplates, будет использован первый.

class Template

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

from django.template import Template

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

За кулисами

Система анализирует исходный код шаблона только один раз — при создании объекта Template. После этого он хранится в виде внутренней структуры дерева для повышения производительности.

Даже сам процесс анализа происходит достаточно быстро. Большая часть анализа выполняется с помощью одного вызова одной короткой регулярной выражения.

Отображение контекста

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

class Context(dict_=None)

Конструктор django.template.Context принимает необязательный аргумент — словарь, сопоставляющий имена переменных со значениями переменных.

Подробности см. в разделе Работа с объектами Context ниже.

Template.render(context)

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

>>> 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», если таковая существует в контексте шаблона.

Система шаблонов использует первый тип поиска, который работает. Это логика короткого замыкания. Вот несколько примеров:

>>> 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. Если у исключения есть атрибут 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, являющийся базовым классом всех исключений API базы данных Django, имеет атрибут silent_variable_failure = True. Таким образом, если вы используете Django-шаблоны с объектами модели Django, исключение DoesNotExist будет проигнорировано.

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

    Хороший пример — метод delete() каждого объекта модели Django. Система шаблонов не должна получать возможность выполнять такие действия:

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

    Чтобы предотвратить это, установите атрибут alters_data на вызываемой переменной. Система шаблонов не будет вызывать переменную, если у неё установлен атрибут alters_data=True, а вместо этого безусловно заменит переменную на string_if_invalid. Динамически сгенерированные методы delete() и save() объектов модели Django автоматически получают атрибут 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 может быть полезным инструментом отладки, не рекомендуется включать его в качестве «по умолчанию для разработки».

Многие шаблоны, включая некоторые шаблоны Django, полагаются на то, что система шаблонов игнорирует несуществующие переменные. Если вы присвоите значение, отличное от '' параметру string_if_invalid, вы столкнетесь с проблемами при отображении этих шаблонов и сайтов.

Как правило, 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:"}}" }}

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

Работа с объектами Context

Большую часть времени вы будете создавать объекты Context передавая в Context() полностью заполненный словарь. Но вы можете добавлять и удалять элементы из объекта Context после его создания, также используя стандартный синтаксис словаря:

>>> 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",
            },
        )

Использование 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 представляет собой список вызываемых функций — так называемых обработчиков контекста — которые принимают объект запроса в качестве аргумента и возвращают словарь элементов, которые должны быть объединены в контекст. В файле настроек по умолчанию сгенерированном по умолчанию, стандартный движок шаблонов содержит следующие обработчики контекста:

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

В дополнение к этому, RequestContext всегда включает 'django.template.context_processors.csrf'. Это обработчик контекста, связанный с безопасностью, необходимый для админской панели и других приложений contrib, и в случае случайной неправильной настройки он намеренно жёстко закодирован и не может быть отключён в опции context_processors.

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

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

Обработчики контекста применяются поверх данных контекста. Это означает, что обработчик контекста может перезаписать переменные, которые вы предоставили своему Context или RequestContext, поэтому будьте внимательны, чтобы не использовать имена переменных, которые совпадают с теми, которые предоставляются обработчиками контекста.

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

from django.template import RequestContext

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

Django делает это, чтобы разрешить данным контекста переопределять обработчики контекста в API, таких как render() и TemplateResponse.

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

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(request)

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

  • user – Экземпляр auth.User, представляющий текущего пользователя (или экземпляр AnonymousUser, если клиент не вошёл в систему).
  • perms – Экземпляр django.contrib.auth.context_processors.PermWrapper, представляющий разрешения, которые имеет текущий вошедший в систему пользователь.

django.template.context_processors.debug

debug(request)

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

  • debug – True. Вы можете использовать это в шаблонах для проверки того, находитесь ли вы в режиме DEBUG.
  • sql_queries – Список словарей {'sql': ..., 'time': ...}, представляющих все запросы SQL, которые произошли до этого момента во время запроса, и сколько времени они заняли. Список упорядочен по псевдониму базы данных, а затем по запросу. Он генерируется по требованию при доступе.

django.template.context_processors.i18n

i18n(request)

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

  • LANGUAGES – Значение параметра настроек LANGUAGES.
  • LANGUAGE_BIDI – True, если текущий язык — язык справа налево, например, иврит, арабский. False если это язык слева направо, например, английский, французский, немецкий.
  • LANGUAGE_CODE – request.LANGUAGE_CODE, если он существует. В противном случае значение параметра настроек LANGUAGE_CODE.

См. теги шаблонов i18n для тегов шаблонов, которые генерируют те же значения.

django.template.context_processors.media

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

django.template.context_processors.static

static(request)

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

django.template.context_processors.csrf

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

django.template.context_processors.request

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

django.template.context_processors.tz

tz(request)

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

django.contrib.messages.context_processors.messages

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

  • messages – Список сообщений (в виде строк), которые были установлены с помощью фреймворка сообщений.
  • DEFAULT_MESSAGE_LEVELS – Карта имён уровней сообщений к их числовому значению.

Написание собственных обработчиков контекста

Обработчик контекста имеет простой интерфейс: это функция Python, которая принимает один аргумент, объект HttpRequest, и возвращает словарь, который добавляется в контекст шаблона.

Например, чтобы добавить параметр настроек DEFAULT_FROM_EMAIL в каждый контекст:

from django.conf import settings


def from_email(request):
    return {
        "DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
    }

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

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

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

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

id="the-dirs-option">Опция DIRS

Укажите Django ваши каталоги шаблонов, используя опцию DIRS в настройке TEMPLATES в файле настроек — или аргумент dirs метода Engine. Это должно быть списком строк, содержащих полные пути к вашим каталогам шаблонов:

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

Ваши шаблоны могут находиться в любом месте, при условии, что каталоги и шаблоны доступны для веб-сервера. Они могут иметь любой расширение, такое как .html или .txt, или не иметь расширения вообще.

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

id="template-loaders">Типы загрузчиков

По умолчанию 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": [BASE_DIR / "templates"],
    }
]

Вы также можете переопределить 'DIRS' и указать определённые каталоги для конкретного загрузчика файловой системы:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "OPTIONS": {
            "loaders": [
                (
                    "django.template.loaders.filesystem.Loader",
                    [BASE_DIR / "templates"],
                ),
            ],
        },
    }
]

django.template.loaders.app_directories.Loader

class app_directories.Loader

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

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

Например, для такой настройки:

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.

Вы можете включить этот загрузчик, установив APP_DIRS в True.

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

django.template.loaders.cached.Loader

class cached.Loader

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

Вы настраиваете загрузчик кэшированных шаблонов со списком других загрузчиков, которые он должен обернуть. Обёрнутые загрузчики используются для поиска неизвестных шаблонов, когда они впервые встречаются. Кэшированный загрузчик затем сохраняет скомпилированные Template в памяти. Экземпляр кэшированных Template возвращается для последующих запросов на загрузку того же шаблона.

Этот загрузчик автоматически включён, если не указана OPTIONS['loaders'].

Вы можете вручную указать кэширование шаблонов с некоторыми пользовательскими загрузчиками шаблонов, используя такие настройки:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [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 4.1:

Кэшированный загрузчик шаблонов был включён, когда OPTIONS['loaders'] не был указан. Раньше он включался только тогда, когда DEBUG был False.

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'. Он использует каждый загрузчик, пока загрузчик не найдёт соответствие.

id="custom-template-loaders">Пользовательские загрузчики

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

id="loader-methods">Методы загрузчика

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() обычно не нужно переопределять.

Разработка собственного

Примеры можно найти в исходном коде встроенных загрузчиков Django.

id="template-origin">Источник шаблона

Шаблоны имеют origin с атрибутами, зависящими от источника, из которого они загружены.

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

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

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

template_name

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

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

loader

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

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

django.template.loaders.cached.Loader требует, чтобы все его обернутые загрузчики устанавливали этот атрибут, обычно путем создания Origin с loader=self.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.2/ref/templates/api/

Spec-Zone.ru

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