Spec-Zone.ru › Django 2.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) [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.

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

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

    Была добавлена возможность включения кэшированного загрузчика шаблонов, когда debug равен False.

  • string_if_invalid — это строка, которую должна использовать система шаблонов для недопустимых (например, с ошибками написания) переменных.

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

    См. Обработка недопустимых переменных шаблона для получения подробной информации.

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

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

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

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

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

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

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

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

static Engine.get_default() [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(), но принимает список имён и возвращает первый найденный шаблон.

END_OF_DOCUMENT_MARKER ```

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

Рекомендуемый способ создания 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

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

  • LANGUAGES – Значение настройки LANGUAGES.
  • LANGUAGE_CODE – request.LANGUAGE_CODE, если он существует. В противном случае значение настройки LANGUAGE_CODE.

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

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, или вообще не иметь расширения.

Обратите внимание, что эти пути должны использовать косые черты (слеши), даже в 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 1.11:

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

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 1.11:

Добавлена автоматическая активация загрузчика кэшированных шаблонов, когда debug равно False.

django.template.loaders.locmem.Loader

class locmem.Loader

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

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

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

Этот загрузчик по умолчанию отключен.

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

Пользовательские загрузчики шаблонов

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

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

get_contents(origin)

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

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

get_template(template_name, skip=None) [source]

Возвращает объект 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) [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.0/ref/templates/api/

Spec-Zone.ru

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