Тема 3 из 6

Шаблоны Jinja

Собирать HTML из строк вручную неудобно и опасно. Во Flask для этого есть шаблоны Jinja — HTML с местами для подстановки данных.

Шаблоны в файлах и в строке

Обычно шаблоны лежат в папке templates рядом с программой:

from flask import render_template


@app.route("/")
def index():
    return render_template("index.html", name="Аня", skills=["Python", "SQL"])

В задачах курса шаблон хранится прямо в коде, в строке — так вся программа в одном файле:

from flask import render_template_string

PAGE = "<h1>Привет, {{ name }}!</h1>"
return render_template_string(PAGE, name="Аня")

Работают обе функции одинаково: шаблон и именованные аргументы — данные для него.

Подстановки, условия и циклы

<h1>{{ title }}</h1>

{% if skills %}
<ul>
  {% for s in skills %}
  <li>{{ loop.index }}. {{ s }}</li>
  {% endfor %}
</ul>
{% else %}
<p>Пока пусто</p>
{% endif %}
  • {{ … }} — вывести значение;
  • {% … %} — команда: if / elif / else / endif, for / endfor;
  • внутри цикла есть loop.index (с единицы), loop.index0 (с нуля), loop.first, loop.last, loop.length;
  • к полям словаря и объекта обращаются через точку: {{ user.name }}.

Фильтры

{{ name|upper }}            АНЯ
{{ name|capitalize }}       Аня
{{ items|length }}          3
{{ items|join(", ") }}      a, b, c
{{ price|round(1) }}        9.9
{{ bio|default("—") }}      если bio не задан

Сортировать и считать лучше в Python, в функции-представлении, а шаблону передавать уже готовые данные: шаблон только показывает.

Экранирование

Всё, что выводится через {{ }}, Flask экранирует: < превращается в &lt;, > — в &gt;, & — в &amp;, кавычки — в &#34; и &#39;. Поэтому, если посетитель впишет в форму <script>…</script>, на странице появится просто текст, а не программа.

Фильтр |safe отключает экранирование. Используйте его только для HTML, который написали вы сами, — никогда для данных от посетителей. Иначе злоумышленник встроит на ваш сайт свой скрипт (атака XSS).

Итог

  • render_template (файл из templates) и render_template_string (строка);
  • {{ }} — значение, {% if %}, {% for %}, loop.index;
  • фильтры upper, capitalize, length, join, default;
  • автоэкранирование защищает от XSS; |safe — только для своего HTML.