Язык шаблонов 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()метод , который Marshals контекст и , возможно , запрос в Contextи делегатов рендеринга к нижележащему Template.

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

Если вы используете DjangoTemplates серверную часть, это, вероятно, не та документация, которую вы ищете. Экземпляр Engineописанного ниже класса доступен с использованием engine атрибута этого бэкэнда, и любые значения атрибутов по умолчанию, упомянутые ниже, переопределяются тем, что передается DjangoTemplates.

classEngine ( 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 %}

staticEngine.get_default ()

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

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

Engine.from_string( template_code )

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

Engine.get_template( имя_шаблона )

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

Engine.select_template( template_name_list )

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

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

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

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

класс Template

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

from django.template import Template

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

За кулисами

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

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

Визуализация контекста

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

classContext ( dict_ = None )

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

Дополнительные сведения см. В разделе « Игра с объектами контекста» ниже.

Template.render( контекст )

Вызовите метод Templateобъекта render()с помощью, 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."

Переменные и поиск

Имена переменных должны состоять из любой буквы (AZ), любой цифры (0–9), символа подчеркивания (но они не должны начинаться с подчеркивания) или точки.

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

  • Поиск по словарю. Пример:foo["bar"]
  • Поиск по атрибутам. Пример:foo.bar
  • Поиск по списку-индексу. Пример:foo[bar]

Обратите внимание, что «bar» в выражении шаблона, например, будет интерпретироваться как буквальная строка и не будет использовать значение переменной «bar», если она существует в контексте шаблона.{{ foo.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, что это базовый класс для всех DoesNotExistисключений API базы данных Django . Так что, если вы используете шаблоны Django с объектами модели Django, любое исключение не сработает.silent_variable_failure = TrueDoesNotExist

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

{% 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( ключ , иначе = Нет )

Возвращает значение keyif keyв контексте, else возвращает otherwise.

Context.setdefault( ключ , по умолчанию = Нет )

Если keyнаходится в контексте, возвращает его значение. В противном случае вставляет key значение defaultи возвращает default.

Context.pop()
Context.push()
исключение 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'

Использование a 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

classRequestContext ( запрос , 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-запросы, которые были выполнены во время запроса, и сколько времени это заняло. Список отсортирован по псевдониму базы данных, а затем по запросу. Он лениво генерируется при доступе.{'sql': ..., 'time': ...}

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объект, и возвращает словарь, который добавляется в контекст шаблона.

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

from django.conf import settings

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

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

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

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

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

класс filesystem.Loader

Загружает шаблоны из файловой системы в соответствии с DIRS.

Этот загрузчик включен по умолчанию. Однако он не найдет никаких шаблонов, пока вы не установите DIRSнепустой список:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [BASE_DIR / 'templates'],
}]

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

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

django.template.loaders.app_directories.Loader

класс 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«s будет загружен первый и ваш будет игнорироваться.

Обратите внимание, что загрузчик выполняет оптимизацию при первом запуске: он кэширует список INSTALLED_APPSпакетов, имеющих templatesподкаталог.

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

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

django.template.loaders.cached.Loader

класс cached.Loader

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

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

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

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

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [BASE_DIR / 'templates'],
    'OPTIONS': {
        'loaders': [
            ('django.template.loaders.cached.Loader', [
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
                'path.to.custom.Loader',
            ]),
        ],
    },
}]

Примечание

Все встроенные теги шаблонов Django можно безопасно использовать с кэшированным загрузчиком, но если вы используете настраиваемые теги шаблонов, поступающие из сторонних пакетов или написанные вами сами, вы должны убедиться, что Nodeреализация каждого тега потокобезопасный. Для получения дополнительной информации см. Соображения безопасности потока тегов шаблона .

django.template.loaders.locmem.Loader

класс 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()методы.

Методы загрузчика

класс Loader

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

get_template_sources( имя_шаблона )

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

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

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

get_contents( происхождение )

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

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

get_template( template_name , skip = None )

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

Необязательный skipаргумент - это список источников, которые следует игнорировать при расширении шаблонов. Это позволяет шаблонам расширять другие шаблоны с тем же именем. Он также используется, чтобы избежать ошибок рекурсии.

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

Создание собственного

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

Источник шаблона

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

classOrigin ( name , template_name = None , loader = None )
name

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

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

template_name

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

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

loader

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

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

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

Copyright ©2021 All rights reserved