Шаблоны¶
Flask использует Jinja2 в качестве шаблонизатора. Разумеется, вы можете использовать другой шаблонизатор, но для работы самого Flask вам все равно придется установить Jinja2. Это требование необходимо для работы богатых расширений. Расширение может зависеть от наличия Jinja2.
Этот раздел дает лишь очень краткое представление о том, как Jinja2 интегрирован во Flask. Если вам нужна информация о синтаксисе самого шаблонизатора, перейдите на официальный сайт Jinja2 Template Documentation для получения дополнительной информации.
Настройка Jinja¶
Если Jinja2 не настроен, Flask конфигурируется следующим образом:
автозавершение включено для всех шаблонов, заканчивающихся на
.html
,.htm
,.xml
,.xhtml
, а также.svg
при использованииrender_template()
.При использовании
render_template_string()
для всех строк включается автозавершение.в шаблоне есть возможность включить/выключить автозавершение с помощью тега
{% autoescape %}
.Flask вставляет пару глобальных функций и помощников в контекст Jinja2, в дополнение к тем значениям, которые присутствуют по умолчанию.
Стандартный контекст¶
Следующие глобальные переменные доступны в шаблонах Jinja2 по умолчанию:
- config
Текущий объект конфигурации (
flask.Flask.config
)Changelog
Изменено в версии 0.10: Теперь это всегда доступно, даже в импортированных шаблонах.
Добавлено в версии 0.6.
- request
Текущий объект запроса (
flask.request
). Эта переменная недоступна, если шаблон был отрисован без активного контекста запроса.
- session
Текущий объект сессии (
flask.session
). Эта переменная недоступна, если шаблон был отрисован без активного контекста запроса.
- g
Связанный с запросом объект для глобальных переменных (
flask.g
). Эта переменная недоступна, если шаблон был отрисован без активного контекста запроса.
- url_for()
Функция
flask.url_for()
.
- get_flashed_messages()
Функция
flask.get_flashed_messages()
.
Поведение контекста Jinja
Эти переменные добавляются в контекст переменных, они не являются глобальными переменными. Разница в том, что по умолчанию они не будут отображаться в контексте импортируемых шаблонов. Отчасти это вызвано соображениями производительности, отчасти для сохранения ясности.
Что это значит для вас? Если у вас есть макрос, который вы хотите импортировать и которому нужен доступ к объекту запроса, у вас есть две возможности:
вы явно передаете макросу в качестве параметра запрос или атрибут интересующего вас объекта запроса.
вы импортируете макрос «с контекстом».
Импорт с контекстом выглядит следующим образом:
{% from '_helpers.html' import my_macro with context %}
Управление автоэскейпом¶
Автоэскейпинг - это концепция автоматического экранирования специальных символов. Специальные символы в смысле HTML (или XML, а значит и XHTML) - это &
, >
, <
, "
, а также '
. Поскольку эти символы сами по себе несут специфическое значение в документах, вы должны заменить их так называемыми «сущностями», если хотите использовать их для текста. Если этого не сделать, то это не только вызовет разочарование пользователей из-за невозможности использовать эти символы в тексте, но и может привести к проблемам безопасности. (см. Межсайтовый скриптинг (XSS))
Однако иногда необходимо отключить автозавершение в шаблонах. Это может произойти, если вы хотите явно внедрить HTML в страницы, например, если они поступают из системы, генерирующей безопасный HTML, например, из конвертера markdown в HTML.
Этого можно достичь тремя способами:
В коде Python оберните строку HTML в объект
Markup
перед тем, как передать ее в шаблон. В целом это рекомендуемый способ.Внутри шаблона используйте фильтр
|safe
, чтобы явно пометить строку как безопасный HTML ({{ myvariable|safe }}
).Временно отключите систему автобегства.
Чтобы отключить систему автоэскейпа в шаблонах, можно использовать блок {% autoescape %}
:
{% autoescape false %}
<p>autoescaping is disabled here
<p>{{ will_not_be_escaped }}
{% endautoescape %}
Когда бы вы это ни делали, пожалуйста, будьте очень осторожны с переменными, которые вы используете в этом блоке.
Регистрация фильтров¶
Если вы хотите зарегистрировать собственные фильтры в Jinja2, у вас есть два способа сделать это. Вы можете либо поместить их вручную в jinja_env
приложения, либо использовать декоратор template_filter()
.
Два следующих примера работают одинаково и оба обращают объект:
@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]
def reverse_filter(s):
return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter
В случае декоратора аргумент необязателен, если вы хотите использовать имя функции в качестве имени фильтра. После регистрации вы можете использовать фильтр в своих шаблонах так же, как и встроенные фильтры Jinja2, например, если у вас есть список Python в контексте под названием mylist:
{% for x in mylist | reverse %}
{% endfor %}
Контекстные процессоры¶
Чтобы автоматически вводить новые переменные в контекст шаблона, во Flask существуют контекстные процессоры. Контекстные процессоры запускаются до отрисовки шаблона и имеют возможность вводить новые значения в контекст шаблона. Контекстный процессор - это функция, которая возвращает словарь. Ключи и значения этого словаря затем объединяются с контекстом шаблона для всех шаблонов в приложении:
@app.context_processor
def inject_user():
return dict(user=g.user)
Приведенный выше контекстный процессор делает переменную user доступной в шаблоне со значением g.user. Этот пример не очень интересен, потому что g все равно доступна в шаблонах, но он дает представление о том, как это работает.
Переменные не ограничиваются значениями; контекстный процессор может также сделать функции доступными для шаблонов (поскольку Python позволяет передавать функции):
@app.context_processor
def utility_processor():
def format_price(amount, currency="€"):
return f"{amount:.2f}{currency}"
return dict(format_price=format_price)
Приведенный выше контекстный процессор делает функцию format_price доступной для всех шаблонов:
{{ format_price(0.33) }}
Вы также могли бы построить format_price как фильтр шаблона (см. Регистрация фильтров), но это демонстрирует, как передавать функции в контекстном процессоре.
Потоковая передача¶
Может быть полезно не выводить весь шаблон в виде одной полной строки, а выводить его в виде потока, создавая небольшие инкрементные строки. Это может использоваться для потоковой передачи HTML кусками для ускорения начальной загрузки страницы или для экономии памяти при рендеринге очень большого шаблона.
Движок шаблонов Jinja2 поддерживает отрисовку шаблона по частям, возвращая итератор строк. Flask предоставляет функции stream_template()
и stream_template_string()
, чтобы упростить использование этой функции.
from flask import stream_template
@app.get("/timeline")
def timeline():
return stream_template("timeline.html")
Эти функции автоматически применяют обертку stream_with_context()
, если запрос активен, так что он остается доступным в шаблоне.