Язык шаблонов Django: для программистов на Python¶
Этот документ объясняет систему шаблонов Django с технической точки зрения - как она работает и как ее расширять. Если вы ищете справку по синтаксису языка, смотрите Язык шаблонов Django.
Она предполагает понимание шаблонов, контекстов, переменных, тегов и рендеринга. Начните с introduction to the Django template language, если вы не знакомы с этими понятиями.
Быстрый обзор¶
Использование системы шаблонов в Python состоит из трех этапов:
- Вы настраиваете
Engine
. - Вы компилируете код шаблона в
Template
. - Вы отображаете шаблон с помощью
Context
.
Проекты Django обычно полагаются на high level, backend agnostic APIs для каждого из этих шагов вместо API нижнего уровня системы шаблонов:
- Для каждого бэкенда
DjangoTemplates
в настройкахTEMPLATES
, Django создаетEngine
.DjangoTemplates
оборачиваетEngine
и адаптирует его к общему API бэкенда шаблона. - Модуль
django.template.loader
предоставляет такие функции, какget_template()
для загрузки шаблонов. Они возвращаютdjango.template.backends.django.Template
, который обертывает фактическийdjango.template.Template
. - Полученный на предыдущем шаге
Template
имеет методrender()
, который маршализирует контекст и, возможно, запрос вContext
и делегирует рендеринг базовомуTemplate
.
Конфигурирование двигателя¶
Если вы используете бэкенд DjangoTemplates
, это, вероятно, не та документация, которую вы ищете. Экземпляр класса Engine
, описанного ниже, доступен с помощью атрибута engine
этого бэкенда, и любые значения атрибутов по умолчанию, упомянутые ниже, переопределяются тем, что передается с помощью DjangoTemplates
.
-
class
Engine
(dirs=None, app_dirs=False, context_processors=None, debug=False, loaders=None, string_if_invalid='', file_charset='utf-8', libraries=None, builtins=None, autoescape=True)[исходный код]¶ При инстанцировании
Engine
все аргументы должны передаваться как аргументы ключевого слова:dirs
- это список директорий, в которых движок должен искать исходные файлы шаблонов. Он используется для настройкиfilesystem.Loader
.По умолчанию это пустой список.
app_dirs
влияет только на значение по умолчаниюloaders
. См. ниже.По умолчанию он равен
False
.autoescape
управляет включением автозавершения HTML.По умолчанию он равен
True
.Предупреждение
Устанавливайте значение
False
, только если вы рендерите не-HTML шаблоны!context_processors
- это список пунктирных Python-путей к вызываемым файлам, которые используются для заполнения контекста, когда шаблон отображается вместе с запросом. Эти callables принимают объект запроса в качестве аргумента и возвращаютdict
элементов, которые должны быть объединены в контекст.По умолчанию это пустой список.
Дополнительную информацию см. в разделе
RequestContext
.debug
- это булево значение, которое включает/выключает режим отладки шаблона. Если значениеTrue
, движок шаблона будет хранить дополнительную отладочную информацию, которая может быть использована для отображения подробного отчета о любом исключении, возникшем во время рендеринга шаблона.По умолчанию он равен
False
.loaders
- это список классов загрузчиков шаблонов, заданных в виде строк. Каждый классLoader
знает, как импортировать шаблоны из определенного источника. По желанию вместо строки может быть использован кортеж. Первым элементом в кортеже должно быть имяLoader
класса, последующие элементы передаютсяLoader
при инициализации.По умолчанию это список, содержащий:
'django.template.loaders.filesystem.Loader'
'django.template.loaders.app_directories.Loader'
тогда и только тогда, когдаapp_dirs
являетсяTrue
.
Эти загрузчики затем оборачиваются в
django.template.loaders.cached.Loader
.Changed in Django 4.1:В старых версиях загрузчик кэшированных шаблонов был включен по умолчанию только в том случае, если
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-путей модулей тегов шаблонов для добавления к built-ins. Например:Engine( builtins=['myapp.builtins'], )
Теги и фильтры из встроенных библиотек можно использовать без предварительного вызова тега
{% load %}
.
-
static
Engine.
get_default
()[исходный код]¶ Возвращает базовый
Engine
от первого сконфигурированногоDjangoTemplates
двигателя. ВызываетImproperlyConfigured
, если ни один двигатель не сконфигурирован.Он необходим для сохранения API, которые полагаются на глобально доступный, неявно сконфигурированный движок. Любое другое использование настоятельно не рекомендуется.
-
Engine.
from_string
(template_code)[исходный код]¶ Компилирует заданный код шаблона и возвращает объект
Template
.
-
Engine.
get_template
(template_name)[исходный код]¶ Загружает шаблон с заданным именем, компилирует его и возвращает объект
Template
.
-
Engine.
select_template
(template_name_list)[исходный код]¶ Подобно
get_template()
, за исключением того, что принимает список имен и возвращает первый найденный шаблон.
Загрузка шаблона¶
Рекомендуемый способ создания Template
- это вызов заводских методов Engine
: get_template()
, select_template()
и from_string()
.
В проекте Django, где в настройках TEMPLATES
определен движок DjangoTemplates
, можно инстанцировать движок Template
напрямую. Если определено более одного движка DjangoTemplates
, будет использоваться первый.
-
class
Template
[исходный код]¶ Этот класс живет по адресу
django.template.Template
. Конструктор принимает один аргумент - необработанный код шаблона:from django.template import Template template = Template("My name is {{ my_name }}.")
За кулисами
Система анализирует ваш необработанный код шаблона только один раз - когда вы создаете объект Template
. С тех пор он хранится внутри в виде древовидной структуры для повышения производительности.
Даже сам синтаксический анализ выполняется довольно быстро. Большая часть разбора происходит через один вызов одного короткого регулярного выражения.
Рендеринг контекста¶
Как только у вас есть скомпилированный объект Template
, вы можете отобразить контекст с ним. Вы можете повторно использовать один и тот же шаблон, чтобы несколько раз отрисовать его с разными контекстами.
-
class
Context
(dict_=None)[исходный код]¶ Конструктор
django.template.Context
принимает необязательный аргумент - словарь, отображающий имена переменных на их значения.Подробнее см. ниже Игра с объектами Context.
-
Template.
render
(context)[исходный код]¶ Вызовите метод
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."
Переменные и поиск¶
Имена переменных должны состоять из любой буквы (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 базы данных DjangoDoesNotExist
, имеетsilent_variable_failure = True
. Поэтому, если вы используете шаблоны Django с объектами модели Django, любое исключениеDoesNotExist
будет провалено молча.Переменная может быть вызвана только в том случае, если у нее нет необходимых аргументов. В противном случае система вернет значение опции движка
string_if_invalid
.
Вызов некоторых переменных может иметь побочные эффекты, и было бы либо глупостью, либо дырой в безопасности разрешить системе шаблонов доступ к ним.
Хорошим примером является метод
delete()
на каждом объекте модели Django. Системе шаблонов не должно быть позволено делать что-то подобное:I will now delete this valuable data. {{ data.delete }}
Чтобы предотвратить это, установите атрибут
alters_data
для вызываемой переменной. Система шаблонов не будет вызывать переменную, если у нее установлен атрибутalters_data=True
, и вместо этого заменит ее наstring_if_invalid
, без всяких условий. Динамически генерируемыеdelete()
иsave()
методы на объектах модели Django получаютalters_data=True
автоматически. Пример:def sensitive_function(self): self.database_record.delete() sensitive_function.alters_data = True
Иногда вы можете захотеть отключить эту возможность по другим причинам и сказать системе шаблонов, чтобы она оставляла переменную без вызова, несмотря ни на что. Для этого установите для вызываемой переменной атрибут
do_not_call_in_templates
со значениемTrue
. Тогда система шаблонов будет действовать так, как будто ваша переменная не вызывается (позволяя вам, например, получить доступ к атрибутам вызываемой переменной).
Как обрабатываются недопустимые переменные¶
Обычно, если переменная не существует, система шаблонов вставляет значение параметра конфигурации движка string_if_invalid
, который по умолчанию установлен на ''
(пустая строка).
Фильтры, применяемые к недопустимой переменной, будут применяться только в том случае, если string_if_invalid
установлено в значение ''
(пустая строка). Если string_if_invalid
установлено в любое другое значение, фильтры переменной будут проигнорированы.
Это поведение немного отличается для тегов шаблонов if
, for
и regroup
. Если в одном из этих тегов шаблонов указана недопустимая переменная, она будет интерпретирована как None
. Фильтры всегда применяются к недопустимым переменным в этих тегах шаблонов.
Если string_if_invalid
содержит '%s'
, маркер формата будет заменен именем недопустимой переменной.
Только для целей отладки!
Хотя string_if_invalid
может быть полезным инструментом отладки, плохой идеей является включение его как «по умолчанию разработки».
Многие шаблоны, включая некоторые шаблоны Django, полагаются на молчание системы шаблонов, когда встречается несуществующая переменная. Если вы присвоите ''
значение, отличное от string_if_invalid
, вы столкнетесь с проблемами рендеринга в этих шаблонах и сайтах.
Как правило, string_if_invalid
следует включать только для отладки конкретной проблемы шаблона, а затем убирать после завершения отладки.
Встроенные переменные¶
Каждый контекст содержит True
, False
и None
. Как и следовало ожидать, эти переменные разрешаются в соответствующие объекты Python.
Ограничения при использовании строковых литералов¶
Язык шаблонов Django не имеет возможности экранировать символы, используемые в его собственном синтаксисе. Например, тег templatetag
необходим, если вам нужно вывести последовательности символов типа {%
и %}
.
Аналогичная проблема возникает, если вы хотите включить эти последовательности в фильтр шаблона или аргументы тегов. Например, при разборе тега block, анализатор шаблонов Django ищет первое вхождение %}
после {%
. Это предотвращает использование "%}"
в качестве строкового литерала. Например, TemplateSyntaxError
будет выдано для следующих выражений:
{% include "template.html" tvar="Some string literal with %} in it." %}
{% with tvar="Some string literal with %} in it." %}{% endwith %}
Та же проблема может возникнуть при использовании зарезервированной последовательности в аргументах фильтра:
{{ some.variable|default:"}}" }}
Если вам нужно использовать строки с этими последовательностями, храните их в переменных шаблона или используйте пользовательский тег шаблона или фильтр, чтобы обойти это ограничение.
Игра с объектами Context
¶
Чаще всего вы создаете объекты Context
, передавая полностью заполненный словарь в Context()
. Но вы можете добавлять и удалять элементы из объекта Context
после его инстанцирования, используя стандартный синтаксис словаря:
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'
-
Context.
get
(key, otherwise=None)¶ Возвращает значение для
key
, еслиkey
находится в контексте, иначе возвращаетotherwise
.
-
Context.
setdefault
(key, default=None)¶ Если
key
находится в контексте, возвращает его значение. В противном случае вставляетkey
со значениемdefault
и возвращаетdefault
.
-
Context.
pop
()¶
-
Context.
push
()¶
-
exception
ContextPopException
[исходный код]¶
Объект Context
является стеком. То есть, вы можете push()
и pop()
его. Если вы pop()
слишком много, это вызовет django.template.ContextPopException
:
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.push()
{}
>>> c['foo'] = 'second level'
>>> c['foo']
'second level'
>>> c.pop()
{'foo': 'second level'}
>>> c['foo']
'first level'
>>> c['foo'] = 'overwritten'
>>> c['foo']
'overwritten'
>>> c.pop()
Traceback (most recent call last):
...
ContextPopException
Вы также можете использовать push()
в качестве менеджера контекста, чтобы обеспечить вызов соответствующего pop()
.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push():
... c['foo'] = 'second level'
... c['foo']
'second level'
>>> c['foo']
'first level'
Все аргументы, переданные в push()
, будут переданы в конструктор dict
, используемый для построения нового контекстного уровня.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push(foo='second level'):
... c['foo']
'second level'
>>> c['foo']
'first level'
-
Context.
update
(other_dict)[исходный код]¶
В дополнение к push()
и pop()
, объект Context
также определяет метод update()
. Он работает как push()
, но принимает в качестве аргумента словарь и заталкивает этот словарь в стек вместо пустого.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'foo': 'updated'})
{'foo': 'updated'}
>>> c['foo']
'updated'
>>> c.pop()
{'foo': 'updated'}
>>> c['foo']
'first level'
Как и push()
, вы можете использовать update()
в качестве менеджера контекста, чтобы обеспечить вызов соответствующего pop()
.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.update({'foo': 'second level'}):
... c['foo']
'second level'
>>> c['foo']
'first level'
Использование Context
в качестве стека пригодится в some custom template tags.
-
Context.
flatten
()¶
Используя метод flatten()
, вы можете получить весь стек Context
в виде одного словаря, включая встроенные переменные.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'bar': 'second level'})
{'bar': 'second level'}
>>> c.flatten()
{'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}
Метод flatten()
также внутренне используется для того, чтобы сделать объекты Context
сравнимыми.
>>> c1 = Context()
>>> c1['foo'] = 'first level'
>>> c1['bar'] = 'second level'
>>> c2 = Context()
>>> c2.update({'bar': 'second level', 'foo': 'first level'})
{'foo': 'first level', 'bar': 'second level'}
>>> c1 == c2
True
Результат flatten()
может быть полезен в модульных тестах для сравнения Context
с dict
:
class ContextTest(unittest.TestCase):
def test_against_dictionary(self):
c1 = Context()
c1['update'] = 'value'
self.assertEqual(c1.flatten(), {
'True': True,
'None': None,
'False': False,
'update': 'value',
})
Использование RequestContext
¶
-
class
RequestContext
(request, dict_=None, processors=None)[исходный код]¶
Django поставляется со специальным классом Context
, django.template.RequestContext
, который действует несколько иначе, чем обычный django.template.Context
. Первое отличие заключается в том, что он принимает HttpRequest
в качестве первого аргумента. Например:
c = RequestContext(request, {
'foo': 'bar',
})
Второе отличие заключается в том, что он автоматически заполняет контекст несколькими переменными в соответствии с опцией конфигурации движка context_processors
.
Опция context_processors
представляет собой список вызываемых таблиц – называемых контекстными процессорами – которые принимают объект запроса в качестве аргумента и возвращают словарь элементов, которые должны быть объединены в контекст. В сгенерированном по умолчанию файле настроек шаблонизатор по умолчанию содержит следующие контекстные процессоры:
[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
В дополнение к ним, RequestContext
всегда включает 'django.template.context_processors.csrf'
. Это контекстный процессор, связанный с безопасностью, необходимый администратору и другим приложениям, и, на случай случай случайной неправильной конфигурации, он намеренно жестко закодирован и не может быть отключен в опции context_processors
.
Каждый процессор применяется по порядку. Это означает, что если один процессор добавляет переменную в контекст, а второй процессор добавляет переменную с тем же именем, то второй отменяет первый. Процессоры по умолчанию описаны ниже.
Когда применяются контекстные процессоры
Контекстные процессоры применяются поверх контекстных данных. Это означает, что контекстный процессор может перезаписать переменные, которые вы предоставили в Context
или RequestContext
, поэтому старайтесь избегать имен переменных, которые пересекаются с именами, предоставленными вашими контекстными процессорами.
Если вы хотите, чтобы контекстные данные имели приоритет над контекстными процессорами, используйте следующий шаблон:
from django.template import RequestContext
request_context = RequestContext(request)
request_context.push({"my_name": "Adrian"})
Django делает это для того, чтобы контекстные данные могли переопределять контекстные процессоры в таких API, как render()
и TemplateResponse
.
Кроме того, вы можете передать RequestContext
список дополнительных процессоров, используя дополнительный, третий позиционный аргумент processors
. В этом примере экземпляр RequestContext
получает переменную ip_address
:
from django.http import HttpResponse
from django.template import RequestContext, Template
def ip_address_processor(request):
return {'ip_address': request.META['REMOTE_ADDR']}
def client_ip_view(request):
template = Template('{{ title }}: {{ ip_address }}')
context = RequestContext(request, {
'title': 'Your IP Address',
}, [ip_address_processor])
return HttpResponse(template.render(context))
Встроенные контекстные процессоры шаблонов¶
Вот что делает каждый из встроенных процессоров:
django.contrib.auth.context_processors.auth
¶
-
auth
(request)[исходный код]¶
Если этот процессор включен, то каждый RequestContext
будет содержать эти переменные:
user
– Экземплярauth.User
, представляющий текущего зарегистрированного пользователя (или экземплярAnonymousUser
, если клиент не зарегистрирован).perms
– Экземплярdjango.contrib.auth.context_processors.PermWrapper
, представляющий разрешения, которые имеет вошедший в систему пользователь.
django.template.context_processors.debug
¶
-
debug
(request)[исходный код]¶
Если этот процессор включен, каждый RequestContext
будет содержать эти две переменные - но только если в настройках DEBUG
установлено значение True
и IP-адрес запроса (request.META['REMOTE_ADDR']
) находится в настройках INTERNAL_IPS
:
debug
–True
. Вы можете использовать это в шаблонах для проверки того, находитесь ли вы в режимеDEBUG
.sql_queries
– Список словарей{'sql': ..., 'time': ...}
, представляющих каждый SQL-запрос, который произошел до сих пор во время запроса, и сколько времени он занял. Список упорядочен по псевдониму базы данных, а затем по запросу. Он лениво генерируется при доступе.
django.template.context_processors.i18n
¶
-
i18n
(request)[исходный код]¶
Если этот процессор включен, то каждый RequestContext
будет содержать эти переменные:
LANGUAGES
– Значение настройкиLANGUAGES
.LANGUAGE_BIDI
–True
если текущий язык является языком справа налево, например, иврит, арабский.False
если это язык слева направо, например, английский, французский, немецкий.LANGUAGE_CODE
–request.LANGUAGE_CODE
, если он существует. В противном случае значение параметраLANGUAGE_CODE
.
Смотрите i18n template tags для тегов шаблонов, которые генерируют те же значения.
django.template.context_processors.media
¶
Если этот процессор включен, то каждый RequestContext
будет содержать переменную MEDIA_URL
, обеспечивающую значение параметра MEDIA_URL
.
django.template.context_processors.static
¶
-
static
(request)[исходный код]¶
Если этот процессор включен, то каждый RequestContext
будет содержать переменную STATIC_URL
, обеспечивающую значение параметра STATIC_URL
.
django.template.context_processors.csrf
¶
Этот процессор добавляет маркер, который необходим тегу шаблона csrf_token
для защиты от Cross Site Request Forgeries.
django.template.context_processors.request
¶
Если этот процессор включен, то каждый RequestContext
будет содержать переменную request
, которая является текущим HttpRequest
.
django.template.context_processors.tz
¶
-
tz
(request)[исходный код]¶
Если этот процессор включен, то каждый RequestContext
будет содержать переменную TIME_ZONE
, предоставляющую имя активного в данный момент часового пояса.
django.contrib.messages.context_processors.messages
¶
Если этот процессор включен, то каждый RequestContext
будет содержать эти две переменные:
messages
– Список сообщений (в виде строк), которые были заданы через messages framework.DEFAULT_MESSAGE_LEVELS
– Сопоставление имен уровней сообщений с their numeric value.
Написание собственных контекстных процессоров¶
Контекстный процессор имеет простой интерфейс: Это функция Python, которая принимает один аргумент, объект HttpRequest
, и возвращает словарь, который добавляется к контексту шаблона.
Например, чтобы добавить параметр DEFAULT_FROM_EMAIL
к каждому контексту:
from django.conf import settings
def from_email(request):
return {
"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
}
Пользовательские контекстные процессоры могут находиться где угодно в вашей кодовой базе. Все, о чем заботится Django, это то, что на ваши пользовательские контекстные процессоры указывает опция 'context_processors'
в вашей настройке TEMPLATES
- или аргумент context_processors
в Engine
, если вы используете его напрямую.
Загрузка шаблонов¶
Как правило, вы будете хранить шаблоны в файлах в вашей файловой системе, а не использовать низкоуровневый API Template
самостоятельно. Сохраняйте шаблоны в каталоге, указанном как каталог шаблонов.
Django ищет каталоги шаблонов в нескольких местах, в зависимости от ваших настроек загрузки шаблонов (см. «Типы загрузчиков» ниже), но самый основной способ указания каталогов шаблонов - это использование опции DIRS
.
Опция DIRS
¶
Сообщите Django, какие у вас есть каталоги шаблонов, используя опцию DIRS
в параметре TEMPLATES
в вашем файле настроек - или аргумент dirs
в Engine
. Это должно быть установлено в список строк, содержащих полные пути к вашим каталогам шаблонов:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'/home/html/templates/lawrence.com',
'/home/html/templates/default',
],
},
]
Ваши шаблоны могут располагаться где угодно, лишь бы каталоги и шаблоны были читаемы веб-сервером. Они могут иметь любое расширение по вашему желанию, например .html
или .txt
, или вообще не иметь расширения.
Обратите внимание, что эти пути должны использовать прямые косые черты в стиле Unix, даже в Windows.
Типы погрузчиков¶
По умолчанию Django использует загрузчик шаблонов на основе файловой системы, но Django поставляется с несколькими другими загрузчиками шаблонов, которые умеют загружать шаблоны из других источников.
Некоторые из этих других загрузчиков отключены по умолчанию, но вы можете активировать их, добавив опцию 'loaders'
к вашему бэкенду DjangoTemplates
в настройках TEMPLATES
или передав аргумент loaders
в Engine
. loaders
должен представлять собой список строк или кортежей, где каждый представляет класс загрузчика шаблонов. Вот загрузчики шаблонов, которые поставляются с Django:
django.template.loaders.filesystem.Loader
-
class
filesystem.
Loader
¶ Загружает шаблоны из файловой системы, согласно
DIRS
.Этот загрузчик включен по умолчанию. Однако он не найдет ни одного шаблона, пока вы не установите
DIRS
в непустой список:TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], }]
Вы также можете переопределить
'DIRS'
и указать конкретные каталоги для конкретного загрузчика файловой системы:TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ( 'django.template.loaders.filesystem.Loader', [BASE_DIR / 'templates'], ), ], }, }]
django.template.loaders.app_directories.Loader
-
class
app_directories.
Loader
¶ Загружает шаблоны из приложений Django в файловой системе. Для каждого приложения в
INSTALLED_APPS
, загрузчик ищет подкаталогtemplates
. Если каталог существует, Django ищет шаблоны в нем.Это означает, что вы можете хранить шаблоны вместе с вашими отдельными приложениями. Это также помогает распространять приложения Django с шаблонами по умолчанию.
Например, для этой настройки:
INSTALLED_APPS = ['myproject.polls', 'myproject.music']
…тогда
get_template('foo.html')
будет искатьfoo.html
в этих каталогах, в этом порядке:/path/to/myproject/polls/templates/
/path/to/myproject/music/templates/
… и будет использовать тот, который найдет первым.
Порядок
INSTALLED_APPS
имеет значение! Например, если вы хотите настроить админку Django, вы можете переопределить стандартный шаблонadmin/base_site.html
изdjango.contrib.admin
своим собственнымadmin/base_site.html
вmyproject.polls
. Затем вы должны убедиться, что вашmyproject.polls
идет передdjango.contrib.admin
вINSTALLED_APPS
, иначеdjango.contrib.admin
будет загружен первым, а ваш будет проигнорирован.Обратите внимание, что при первом запуске загрузчик выполняет оптимизацию: он кэширует список того, какие
INSTALLED_APPS
пакеты имеютtemplates
подкаталог.Вы можете включить этот загрузчик, установив
APP_DIRS
вTrue
:TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'APP_DIRS': True, }]
django.template.loaders.cached.Loader
-
class
cached.
Loader
¶ Хотя система шаблонов Django довольно быстрая, если ей нужно читать и компилировать ваши шаблоны каждый раз, когда они отображаются, накладные расходы могут увеличиться.
Вы настраиваете загрузчик кэшированных шаблонов со списком других загрузчиков, которые он должен обернуть. Обернутые загрузчики используются для поиска неизвестных шаблонов при их первом обнаружении. Кэшированный загрузчик затем сохраняет скомпилированный
Template
в памяти. Кэшированный экземплярTemplate
возвращается при последующих запросах на загрузку того же шаблона.Этот загрузчик включается автоматически, если не указано
OPTIONS['loaders']
.Вы можете вручную задать кэширование шаблонов с помощью некоторых пользовательских загрузчиков шаблонов, используя такие настройки:
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], 'OPTIONS': { 'loaders': [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', 'path.to.custom.Loader', ]), ], }, }]
Примечание
Все встроенные теги шаблонов Django безопасны для использования с кэшированным загрузчиком, но если вы используете пользовательские теги шаблонов, полученные из сторонних пакетов или написанные вами самостоятельно, вы должны убедиться, что реализация
Node
для каждого тега является потокобезопасной. Для получения дополнительной информации см. раздел template tag thread safety considerations.Changed in Django 4.1:Кэшированный загрузчик шаблонов был включен всякий раз, когда
OPTIONS['loaders']
не указан. Ранее он был включен только тогда, когда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
[исходный код]¶ Загружает шаблоны из заданного источника, например, из файловой системы или базы данных.
-
get_template_sources
(template_name)[исходный код]¶ Метод, который принимает
template_name
и выдаетOrigin
экземпляров для каждого возможного источника.Например, загрузчик файловой системы может получить
'index.html'
в качестве аргументаtemplate_name
. Этот метод выдаст исходные данные для полного путиindex.html
, как он появляется в каждом каталоге шаблонов, который просматривает загрузчик.Метод не обязан проверять, существует ли шаблон по заданному пути, но он должен убедиться, что путь действителен. Например, загрузчик файловой системы проверяет, что путь лежит в допустимом каталоге шаблона.
-
get_contents
(origin)¶ Возвращает содержимое для шаблона, заданного экземпляром
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()
обычно не нужно переопределять.
-
Постройте свой собственный
В качестве примера можно привести source code for Django’s built-in loaders.
Происхождение шаблона¶
Шаблоны имеют origin
, содержащие атрибуты в зависимости от источника, из которого они загружены.
-
class
Origin
(name, template_name=None, loader=None)[исходный код]¶ -
name
¶ Путь к шаблону, возвращенный загрузчиком шаблонов. Для загрузчиков, считывающих данные из файловой системы, это полный путь к шаблону.
Если шаблон инстанцируется напрямую, а не через загрузчик шаблонов, это строковое значение
<unknown_source>
.
-
template_name
¶ Относительный путь к шаблону, переданный в загрузчик шаблонов.
Если шаблон инстанцируется напрямую, а не через загрузчик шаблонов, то это
None
.
-
loader
¶ Экземпляр загрузчика шаблонов, который создал этот
Origin
.Если шаблон инстанцируется напрямую, а не через загрузчик шаблонов, то это
None
.django.template.loaders.cached.Loader
требует, чтобы все его обернутые загрузчики устанавливали этот атрибут, обычно путем инстанцированияOrigin
сloader=self
.
-