Spec-Zone.ru › Django 2.1

Язык шаблонов 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) [source]

При создании экземпляра 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() [source]

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

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

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

В более старых версиях вызывает ImproperlyConfigured, если настроены несколько движков, а не возвращает первый движок.

Engine.from_string(template_code) [source]

Компилирует заданный код шаблона и возвращает объект Template.

Engine.get_template(template_name) [source]

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

Engine.select_template(template_name_list) [source]

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

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

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

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

class Template [source]

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

from django.template import Template

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

За кулисами

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

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

Вывод контекста

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

class Context(dict_=None) [source]

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

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

Template.render(context) [source]

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

Многие шаблоны, включая те, что используются в панели администратора, полагаются на бездействие системы шаблонов при встрече с несуществующей переменной. Если вы присвоите значение, отличное от '' параметру 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 [source]

Объект 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) [source]

В дополнение к 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) [source]

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() [source]

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

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

django.template.context_processors.debug

debug() [source]

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

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

django.template.context_processors.i18n

i18n() [source]

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

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

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

django.contrib.messages.context_processors.messages

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

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

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

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

Пользовательские процессоры контекста могут находиться в любом месте вашей кодовой базы. 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 [source]

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

get_template_sources(template_name) [source]

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

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

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

get_contents(origin)

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

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

get_template(template_name, skip=None) [source]

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

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

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

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

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

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

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

class Origin(name, template_name=None, loader=None) [source]
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/2.1/ref/templates/api/

Spec-Zone.ru

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