Spec-Zone.ru › Django 5.0

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

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

    См. 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.

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

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

В проекте 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': ...}, представляющих все запросы к базе данных, произошедшие до сих пор во время запроса, и сколько времени они заняли. Список упорядочен по алиасу базы данных, а затем по запросу. Он создаётся лениво при доступе.

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.

Опция 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.

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

По умолчанию 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.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 аргумента. Этот метод вернёт объекты Origin для полного пути к index.html в каждом каталоге шаблонов, просматриваемом загрузчиком.

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

get_contents(origin)

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

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

get_template(template_name, skip=None)

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

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

В общем случае достаточно определить get_template_sources() и get_contents() для пользовательских загрузчиков шаблонов. get_template() обычно переопределять не нужно.

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

Для примеров, прочитайте исходный код встроенных загрузчиков Django.

Происхождение шаблона

Шаблоны содержат 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/5.0/ref/templates/api/

Spec-Zone.ru

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