Spec-Zone.ru › Django 3.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. Полученный на предыдущем шаге объект имеет метод 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.

    Если debug равно False, эти загрузчики обернуты в 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().

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 DoesNotExist, имеет 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()

Если этот обработчик включен, каждый 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:

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

django.template.context_processors.i18n

i18n()

Если этот обработчик включен, каждый 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()

Если этот обработчик включен, каждый 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()

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

django.contrib.messages.context_processors.messages

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

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

Создание собственных обработчиков контекста

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

END_OF_DOCUMENT_MARKER

Пользовательские обработчики контекста могут находиться где угодно в вашем коде. 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': [os.path.join(BASE_DIR, 'templates')],
}]

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

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 ищет шаблоны там.

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

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

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

Этот загрузчик автоматически включен, если OPTIONS['loaders'] не указан и OPTIONS['debug'] равно False (последний параметр по умолчанию равен значению DEBUG).

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

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 аргумента. Этот метод вернёт объекты `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/3.0/ref/templates/api/

Spec-Zone.ru

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