Шаблоны

Flask использует в качестве системы шаблонизации Jinja2. Можно использовать другие системы шаблонизации, но для запуска Flask всё равно необходимо установить Jinja2. Это необходимо для использования дополнительных возможностей. Расширения могут зависеть от наличия Jinja2.

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

Установка Jinja

По умолчанию Flask настраивает Jinja2 следующим образом:

  • включено автоматическое экранирование для всех шаблонов, с расширениями .html, .htm, .xml, .xhtml
  • шаблон может включать или отключать автоматическое экранирование при помощи тега {% autoescape %}.
  • Flask добавляет пару функций и хелперов в контекст Jinja2, дополнительно к значениям, имеющимся по умолчанию.

Стандартный контекст

По умолчанию из шаблонов Jinja2 доступны следующие глобальные переменные:

config

Объект текущей конфигурации (flask.config)

Добавлено в версии 0.6.

Изменено в версии 0.10: Теперь он доступен всегда, даже в импортированных шаблонах.

request

Объект текущего запроса (flask.request). Эта переменная недоступна, если шаблон отрисован без контекста активного запроса.

session

Объект текущего сеанса (flask.session). Эта переменная недоступна, если шаблон отрисован без контекста активного запроса.

g

Связанный с запросом объект с глобальными переменными (flask.g). Эта переменная недоступна, если шаблон отрисован без контекста активного запроса.

url_for()

Функция flask.url_for().

get_flashed_messages()

Функция flask.get_flashed_messages().

Контекстное поведение Jinja

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

Какое это имеет значение? Если вам нужно получить доступ из макроса к объекту запроса, есть две возможности:

  1. явным образом передать объект запроса или его атрибут в макрос в качестве параметра.
  2. импортировать макрос с контекстом, указав ключевые слова “with context”.

Импорт с контекстом выглядит следующим образом:

{% from '_helpers.html' import my_macro with context %}

Стандартные фильтры

В дополнение к собственным фильтрам Jinja2, доступны следующие фильтры:

tojson()

Эта функция конвертирует переданный объект в JSON-представление. Это может быть полезно, когда нужно на лету сгенерировать JavaScript.

Отметим, что внутри тегов script не должно производиться экранирование, поэтому убедитесь в том, что отключили экранирование при помощи фильтра |safe (ранее версии Flask 0.10), если собираетесь использовать фильтр tojson внутри тегов script:

<script type=text/javascript>
    doSomethingWith({{ user.username|tojson|safe }});
</script>

Управление автоэкранированием

Автоэкранирование - это автоматическое экранирование специальных символов. Специальными символами в 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:

@app.context_processor
def inject_user():
    return dict(user=g.user)

Процессор контекста, приведённый выше, сделает переменную g.user доступной из шаблона под именем user. Этот пример не очень интересен, поскольку g и так доступна в шаблонах, но даёт представление о том, как это работает.

Переменные не ограничены только своими значениями; процессор контекста может передавать в шаблон не только переменные, но и функции (поскольку Python позволяет передавать функции):

@app.context_processor
def utility_processor():
    def format_price(amount, currency=u'€'):
        return u'{0:.2f}{1}'.format(amount, currency)
    return dict(format_price=format_price)

Вышеприведённый процессор контекста сделает функцию format_price доступной для всех шаблонов:

{{ format_price(0.33) }}

Вы также можете встроить format_price как фильтр шаблона (см. выше раздел Регистрация фильтров), но этот пример демонстрирует, как передавать функции в контекст шаблона.

Оригинал этой страницы