Как использовать шаблоны в приложении Flask

Автор выбрал Фонд свободного и открытого ПО для получения пожертвования в рамках программы Write for DOnations.

Введение

Flask — это легковесный веб-фреймворк на Python, предоставляющий полезные инструменты и функции для создания веб-приложений на языке Python.

При разработке веб-приложения важно разделять бизнес-логику и логику представления. Бизнес-логика отвечает за обработку запросов пользователей и взаимодействие с базой данных для формирования подходящего ответа. Логика представления определяет, как данные представлены пользователю, обычно используя HTML-файлы для построения базовой структуры веб-страницы ответа и CSS-стили для оформления HTML-компонентов. Например, в социальной сети вы можете иметь поле для имени пользователя и пароля, которое отображается только когда пользователь не авторизован. Если пользователь авторизован, вместо этого отображается кнопка выхода. Это логика представления. Если пользователь вводит свое имя пользователя и пароль, вы можете использовать Flask для выполнения бизнес-логики: извлечения данных (имени пользователя и пароля) из запроса, авторизации пользователя, если учетные данные верны, или отправки сообщения об ошибке. Как будет отображаться сообщение об ошибке, будет решать логика представления.

В Flask вы можете использовать язык шаблонов Jinja для рендеринга HTML-шаблонов. Шаблон — это файл, который может содержать как фиксированное, так и динамическое содержимое. Когда пользователь запрашивает что-то из вашего приложения (например, главную страницу или страницу входа), Jinja позволяет вам отвечать HTML-шаблоном, где вы можете использовать множество функций, недоступных в стандартном HTML, таких как переменные, операторы if, циклы for, фильтры и наследование шаблонов. Эти функции позволяют вам эффективно писать легко поддерживаемые HTML-страницы. Jinja также автоматически экранирует HTML, чтобы предотвратить атаки межсайтовым скриптингом (XSS).

В этом уроке вы создадите небольшое веб-приложение, которое будет рендерить несколько HTML-файлов. Вы будете использовать переменные для передачи данных с сервера в шаблоны. Наследование шаблонов поможет вам избежать повторений. Вы будете использовать логику в шаблонах, такую как условные операторы и циклы, фильтры для модификации текста и набор инструментов Bootstrap для стилизации вашего приложения.

Предварительные требования

Шаг 1 — Рендеринг шаблона и использование переменных

Убедитесь, что вы активировали свою среду и установили Flask, а затем вы можете начать создание вашего приложения. Первым шагом является отображение сообщения, которое приветствует посетителей на главной странице. Вы будете использовать вспомогательную функцию Flask render_template() для обслуживания HTML-шаблона в качестве ответа. Вы также увидите, как передавать переменные из вашего приложения в шаблоны.

Сначала в вашем каталоге flask_app откройте файл с именем app.py для редактирования. Используйте nano или ваш любимый текстовый редактор:

  1. nano app.py

Добавьте следующий код внутри файла app.py:

flask_app/app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello():
    return render_template('index.html')

Сохраните и закройте файл.

В этом блоке кода вы импортируете класс Flask и функцию render_template() из пакета flask. Вы используете класс Flask для создания экземпляра вашего Flask-приложения с именем app. Затем вы определяете функцию представления (которая является Python-функцией, возвращающей HTTP-ответ) под названием hello() с помощью декоратора app.route(), который превращает обычную функцию в функцию представления. Эта функция представления использует функцию render_template() для рендеринга шаблона с именем index.html.

Далее вам нужно создать файл шаблона index.html в директории под названием templates внутри вашей директории flask_app. Flask ищет шаблоны в директории templates, которая называется templates, поэтому имя важно. Убедитесь, что вы находитесь внутри директории flask_app, и выполните следующую команду для создания директории templates:

  1. mkdir templates

Затем откройте файл под названием index.html внутри директории templates для редактирования. Имя index.html здесь не является обязательным стандартным именем; вы можете назвать его home.html или homepage.html, или что-то еще, если хотите:

  1. nano templates/index.html

Добавьте следующий HTML-код внутрь файла index.html:

flask_app/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
</body>
</html>

Здесь вы установили заголовок, добавили сообщение Hello World! как заголовок H1, и создали сообщение Welcome to FlaskApp! как заголовок H2.

Сохраните и закройте файл.

Находясь в директории flask_app с активированным виртуальным окружением, сообщите Flask о приложении (app.py в вашем случае), используя переменную окружения FLASK_APP, и установите переменную окружения FLASK_ENV в development, чтобы запустить приложение в режиме разработки и получить доступ к отладчику. Используйте следующие команды для этого (на Windows используйте set вместо export):

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

Затем запустите приложение с помощью команды flask run:

  1. flask run

С запущенным сервером разработки, посетите следующий URL с помощью вашего браузера:

http://127.0.0.1:5000/

Вы увидите, что заголовок страницы установлен в FlaskApp, и два заголовка отображаются как HTML.

В веб-приложениях часто требуется передавать данные из файлов Python вашего приложения в HTML-шаблоны. Чтобы продемонстрировать, как это сделать в данном приложении, вы передадите переменную, содержащую текущую дату и время UTC, в шаблон index, и отобразите значение переменной в шаблоне.

Оставьте сервер запущенным и откройте файл app.py для редактирования в новом терминале:

  1. nano app.py

Импортируйте модуль datetime из стандартной библиотеки Python и отредактируйте функцию index() так, чтобы файл выглядел следующим образом:

flask_app/app.py
import datetime
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello():
    return render_template('index.html', utc_dt=datetime.datetime.utcnow())

Сохраните и закройте файл.

Здесь вы импортировали модуль datetime и передали переменную с именем utc_dt в шаблон index.html со значением datetime.datetime.utcnow(), которое представляет текущую дату и время UTC.

Далее, чтобы отобразить значение переменной на главной странице, откройте файл index.html для редактирования:

  1. nano templates/index.html

Отредактируйте файл, чтобы он выглядел следующим образом:

flask_app/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
</body>
</html>

Сохраните и закройте файл.

Вы добавили заголовок H3 с специальным разделителем {{ ... }} для вывода значения переменной utc_dt.

Откройте браузер и посетите главную страницу:

http://127.0.0.1:5000/

Вы увидите страницу, похожую на следующее изображение:

Вы создали индексную страницу с HTML-шаблоном в своем приложении Flask, отобразили шаблон и передали и отобразили значение переменной. Далее вы избежите повторения кода, используя наследование шаблонов.

Шаг 2 — Использование наследования шаблонов

На этом шаге вы создадите базовый шаблон с содержимым, которое может быть использовано в других ваших шаблонах. Вы отредактируете шаблон index, чтобы он наследовался от базового шаблона. Затем вы создадите новую страницу, которая будет служить страницей “О приложении” вашего приложения, где пользователи смогут найти больше информации о вашем приложении.

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

Сначала откройте новый файл под названием base.html для редактирования в вашем каталоге шаблонов:

  1. nano templates/base.html

Напишите следующий код в вашем файле base.html:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="#">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Сохраните и закройте файл.

Большая часть кода в этом файле является стандартным HTML, заголовком, некоторыми стилями для навигационных ссылок, навигационной панелью с двумя ссылками, одной для главной страницы и одной для страницы “О приложении”, которая еще не создана, и <div> для содержимого страницы. (Ссылки пока не работают; следующий шаг покажет, как связывать страницы).

Однако следующие выделенные части специфичны для движка шаблонов Jinja:

  • {% block title %} {% endblock %}: Блок, который служит заполнителем для заголовка. Вы будете использовать его в других шаблонах, чтобы предоставить индивидуальный заголовок для каждой страницы в вашем приложении, не переписывая каждый раз весь раздел <head>.

  • {% block content %} {% endblock %}: Еще один блок, который будет заменен содержимым в зависимости от дочернего шаблона (шаблона, который наследуется от base.html), который его переопределит.

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

  1. nano templates/index.html

Затем замените его содержимое следующим:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Index {% endblock %}</h1>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
{% endblock %}

Здесь вы используете тег `{% extends %}` для наследования от шаблона `base.html`. Затем вы расширяете его, заменяя блок `content` в базовом шаблоне на содержимое блока `content` в предыдущем блоке кода.

Этот блок содержит тег `<h1>` с текстом `Index` внутри блока title, который, в свою очередь, заменяет оригинальный блок `title` в шаблоне `base.html` текстом `Index`, так что полный заголовок становится `Index - FlaskApp`. Таким образом, вы можете избежать повторения одного и того же текста дважды, так как он выполняет роль как заголовка страницы, так и заголовка, который появляется под навигационной панелью, унаследованной от базового шаблона.

Затем у вас есть еще несколько заголовков: один заголовок `<h1>` с текстом `Hello World!`, заголовок `<h2> и заголовок `<h3>`, содержащий значение переменной `utc_dt`.

Наследование шаблонов дает вам возможность повторно использовать HTML-код, который у вас есть в других шаблонах (`base.html` в данном случае), не повторяя его каждый раз, когда он нужен.

Сохраните и закройте файл, а затем обновите страницу index в своем браузере. Страница будет выглядеть следующим образом:

Далее вы создадите страницу About. Откройте файл `app.py`, чтобы добавить новую маршрутизацию:

  1. nano app.py

Добавьте следующий маршрут в конец файла:

flask_app/app.py

# ...
@app.route('/about/')
def about():
    return render_template('about.html')

Здесь вы используете декоратор app.route() для создания функции-представления под названием about(). В ней вы возвращаете результат вызова функции render_template() с именем файла шаблона about.html в качестве аргумента.

Сохраните и закройте файл.

Откройте файл шаблона под названием about.html для редактирования:

  1. nano templates/about.html

Добавьте следующий код в файл:

flask_app/templates/about.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} About {% endblock %}</h1>
    <h3>FlaskApp is a Flask web application written in Python.</h3>
{% endblock %}

Здесь вы наследуетесь от базового шаблона с помощью тега extends, заменяете блок content базового шаблона на тег <h1>, который также служит заголовком страницы, и добавляете тег <h3> с некоторыми сведениями о приложении.

Сохраните и закройте файл.

С запущенным сервером разработки посетите следующий URL в своем браузере:

http://127.0.0.1:5000/about

Вы увидите страницу, похожую на следующую:

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

Теперь вы создали базовый шаблон и использовали его на своей главной странице и странице “О нас”, чтобы избежать повторения кода. Ссылки в навигационной панели на данный момент ничего не делают. На следующем этапе вы узнаете, как связывать маршруты в своих шаблонах, исправляя ссылки в навигационной панели.

Шаг 3 — Связывание между страницами

На этом этапе вы узнаете, как связывать страницы в своих шаблонах с помощью вспомогательной функции url_for(). Вы добавите два ссылки в панель навигации вашего базового шаблона, одну для главной страницы и одну для страницы “О нас”.

Сначала откройте ваш базовый шаблон для редактирования:

  1. nano templates/base.html

Отредактируйте файл, чтобы он выглядел следующим образом:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Здесь вы используете специальную функцию url_for(), которая возвращает URL для функции представления, которую вы ей передаете. Первая ссылка ведет к маршруту функции представления hello() (которая является главной страницей). Вторая ссылка ведет к маршруту функции представления about(). Обратите внимание, что вы передаете имя функции представления, а не маршрут (/ или /about).

Использование функции url_for() для построения URL помогает лучше управлять URL. Если вы закодируете URL жестко, ваши ссылки могут сломаться, если вы измените маршруты. С url_for() вы можете редактировать маршруты и гарантировать, что ссылки будут работать, как ожидается. Функция url_for() также заботится о других вещах, таких как экранирование специальных символов.

Сохраните и закройте файл.

Теперь перейдите на главную страницу и попробуйте ссылки в панели навигации. Вы увидите, что они работают, как и ожидалось.

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

Шаг 4 — Использование условий и циклов

На этом шаге вы будете использовать операторы if в ваших шаблонах для управления отображением в зависимости от определенных условий. Также вы будете использовать циклы for для перебора списков Python и отображения каждого элемента в списке. Вы добавите новую страницу, которая будет отображать комментарии в виде списка. Комментарии с четным индексом будут иметь синий фон, а комментарии с нечетным индексом будут отображаться с серым фоном.

Сначала вы создадите маршрут для страницы комментариев. Откройте файл app.py для редактирования:

  1. nano app.py

Добавьте следующий маршрут в конец файла:

flask_app/app.py

# ...

@app.route('/comments/')
def comments():
    comments = ['This is the first comment.',
                'This is the second comment.',
                'This is the third comment.',
                'This is the fourth comment.'
                ]

    return render_template('comments.html', comments=comments)

В маршруте выше у вас есть список Python под названием comments, содержащий четыре элемента. (Обычно комментарии берутся из базы данных в реальных сценариях, а не жестко закодированы, как здесь.) В последней строке вы возвращаете файл шаблона под названием comments.html, передавая переменную comments, содержащую список, в файл шаблона.

Сохраните и закройте файл.

Далее откройте новый файл comments.html в директории templates для редактирования:

  1. nano templates/comments.html

Добавьте в файл следующий код:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
        <div style="padding: 10px; background-color: #EEE; margin: 20px">
            <p style="font-size: 24px">{{ comment }}</p>
        </div>
        {% endfor %}
    </div>
{% endblock %}

Здесь вы расширяете шаблон base.html и заменяете содержимое блока content. Сначала вы используете заголовок <h1>, который также служит заголовком страницы.

Вы используете цикл for Jinja в строке {% for comment in comments %} для прохода по каждому комментарию в списке comments (который сохраняется в переменной comment). Вы отображаете комментарий в теге <p style="font-size: 24px">{{ comment }}</p> так же, как обычно отображаете переменную в Jinja. Вы обозначаете конец цикла for с помощью ключевого слова {% endfor %}. Это отличается от конструкции циклов for в Python, поскольку в шаблонах Jinja нет специальных отступов.

Сохраните и закройте файл.

С запущенным сервером разработки откройте браузер и посетите страницу комментариев:

http://127.0.0.1:5000/comments

Вы увидите страницу, похожую на следующую:

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

Откройте файл шаблона comments.html для редактирования:

  1. nano templates/comments.html

Отредактируйте его следующим образом:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index % 2 == 0 %}
                {% set bg_color = '#e6f9ff' %}
            {% else %}
                {% set bg_color = '#eee' %}
            {% endif %}

            <div style="padding: 10px; background-color: {{ bg_color }}; margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

С этим новым изменением вы добавили оператор if в строку {% if loop.index % 2 == 0 %}. Переменная loop является специальной переменной Jinja, которая предоставляет вам доступ к информации о текущем цикле. Здесь вы используете loop.index для получения индекса текущего элемента, который начинается с 1, а не с 0, как в списках Python.

Оператор if здесь проверяет, является ли индекс четным, используя оператор %. Он проверяет остаток от деления индекса на 2; если остаток равен 0, это означает, что индекс четный, в противном случае индекс нечетный. Вы используете тег {% set %} для объявления переменной под названием bg_color. Если индекс четный, вы устанавливаете его в голубой цвет, в противном случае, если индекс нечетный, вы устанавливаете переменную bg_color в серый. Затем вы используете переменную bg_color для установки цвета фона для тега <div>, который содержит комментарий. Над текстом комментария вы используете loop.index для отображения текущего индекса в теге <p>.

Сохраните и закройте файл.

Откройте браузер и перейдите на страницу комментариев:

http://127.0.0.1:5000/comments

Вы увидите свою новую страницу комментариев:

Это была демонстрация использования оператора if. Но вы также можете достичь того же эффекта, используя специальный помощник Jinja loop.cycle(). Чтобы продемонстрировать это, откройте файл comments.html.

  1. nano templates/comments.html
flask_app/templates/comments.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            <div style="padding: 10px;
                        background-color: {{ loop.cycle('#EEE', '#e6f9ff') }};
                        margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

Здесь вы удалили оператор if/else и использовали помощник loop.cycle('#EEE', '#e6f9ff') для чередования между двумя цветами. Значение background-color будет #EEE один раз и #e6f9ff другой.

Сохраните и закройте файл.

Откройте страницу комментариев в браузере, обновите её, и вы увидите, что это имеет тот же эффект, что и оператор if.

Вы можете использовать операторы if для множества целей, включая управление отображением на странице. Например, чтобы отображать все комментарии, кроме второго, вы можете использовать оператор if с условием loop.index != 2 для фильтрации второго комментария.

Откройте шаблон комментариев:

  1. nano templates/comments.html

И отредактируйте его следующим образом:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

Здесь вы используете {% if loop.index != 2 %} для отображения только тех комментариев, у которых индекс не равен 2, что означает все комментарии, кроме второго. Вы также используете жестко заданное значение для цвета фона вместо помощника loop.cycle(), чтобы упростить задачу, и остальное не изменено. Вы завершаете оператор if с помощью {% endif %}.

Сохраните и закройте файл.

Обновите страницу комментариев, и вы увидите, что второй комментарий не отображается.

Теперь вам нужно добавить ссылку, которая будет перенаправлять пользователей на страницу комментариев в навигационной панели. Откройте базовый шаблон для редактирования:

  1. nano templates/base.html

Измените содержимое тега `

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('comments') }}">Comments</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Здесь вы используете помощник `url_for()` для ссылки на функцию представления `comments()`.

Сохраните и закройте файл.

Теперь в панели навигации будет новая ссылка, которая ведет на страницу комментариев.

Вы использовали операторы `if` в своих шаблонах для управления отображением в зависимости от определенных условий. Вы использовали циклы `for` для перебора списков Python и отображения каждого элемента в списке, и вы узнали о специальной переменной `loop` в Jinja. Далее вы будете использовать фильтры Jinja для управления отображением данных переменных.

Шаг 5 — Использование фильтров

На этом шаге вы узнаете, как использовать фильтры Jinja в своих шаблонах. Вы примените фильтр `upper` для преобразования комментариев, добавленных на предыдущем шаге, в верхний регистр, используете фильтр `join` для объединения последовательности строк в одну строку и узнаете, как отображать доверенный HTML-код без его экранирования с помощью фильтра `safe`.

Сначала вы преобразуете комментарии на странице комментариев в верхний регистр. Откройте шаблон `comments.html` для редактирования:

  1. nano templates/comments.html

Измените его следующим образом:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

Здесь вы добавили фильтр upper с помощью символа трубы (|). Это изменит значение переменной comment на верхний регистр.

Сохраните и закройте файл.

С запущенным сервером разработки откройте страницу комментариев в своем браузере:

http://127.0.0.1:5000/comments

Вы можете видеть, что комментарии стали заглавными после применения фильтра.

Фильтры также могут принимать аргументы в скобках. Чтобы продемонстрировать это, вы будете использовать фильтр join для объединения всех комментариев в списке comments.

Откройте шаблон комментариев:

  1. nano templates/comments.html

Отредактируйте его следующим образом:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            <p>{{ comments | join(" | ") }}</p>
        </div>
    </div>
{% endblock %}

Здесь вы добавили тег <hr> и тег <div>, где вы объединяете все комментарии в списке comments с помощью фильтра join().

Сохраните и закройте файл.

Обновите страницу комментариев, и вы увидите страницу, похожую на следующую:

Как видите, список comments отображается с комментариями, разделенными символом трубы, который вы передали в фильтр join().

Еще один важный фильтр — это фильтр safe, который позволяет вам отображать доверенный HTML в браузере. Чтобы проиллюстрировать это, вы добавите в шаблон комментариев некоторый текст, содержащий HTML-тег, используя разделитель {{ }} Jinja. В реальной ситуации это будет передаваться как переменная с сервера. Затем вы измените аргумент join() на тег <hr> вместо символа трубы.

Откройте шаблон комментариев:

  1. nano templates/comments.html

Измените его следующим образом:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" }}
            <p>{{ comments | join(" <hr> ") }}</p>
        </div>
    </div>
{% endblock %}

Здесь вы добавили значение "<h1>COMMENTS</h1>" и изменили аргумент join на тег <hr>.

Сохраните и закройте файл.

Обновите страницу комментариев, и вы увидите страницу, похожую на следующую:

Как видите, HTML-теги не были отображены. Это безопасная функция в Jinja, потому что некоторые HTML-теги могут быть вредными и могут привести к атаке Cross Site Scripting (XSS). Вы должны разрешать отображение только доверенного HTML в браузере.

Чтобы отобразить HTML-теги выше, откройте файл шаблона комментариев:

  1. nano templates/comments.html

Измените его, добавив фильтр safe:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" | safe }}
            <p>{{ comments | join(" <hr> ") | safe }}</p>
        </div>
    </div>
{% endblock %}

Вы можете видеть, что также можно объединять фильтры, как в строке <p>{{ comments | join(" <hr> ") | safe }}</p>. Каждый фильтр применяется к результату предыдущего фильтра.

Сохраните и закройте файл.

Обновите страницу комментариев, и вы увидите, что HTML-теги теперь отображаются так, как ожидалось:

Предупреждение: Использование фильтра safe для HTML из неизвестных источников может подвергнуть ваше приложение атакам XSS. Не используйте его, если HTML, которое вы отображаете, не происходит из доверенного источника.

Для получения дополнительной информации ознакомьтесь с списком встроенных фильтров Jinja.

Теперь вы узнали, как использовать фильтры в ваших шаблонах Jinja для изменения значений переменных. Далее вы интегрируете набор инструментов Bootstrap для оформления вашего приложения.

Шаг 6 — Интеграция Bootstrap

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

Набор инструментов Bootstrap помогает оформить ваше приложение так, чтобы оно выглядело более визуально привлекательно. Он также поможет вам внедрить адаптивные веб-страницы в ваше веб-приложение, чтобы оно хорошо работало на мобильных браузерах, без написания собственного HTML, CSS и JavaScript кода для достижения этих целей.

Чтобы использовать Bootstrap, вам нужно добавить его в базовый шаблон, чтобы вы могли использовать его во всех других шаблонах.

Откройте шаблон base.html для редактирования:

  1. nano templates/base.html

Отредактируйте его, чтобы он выглядел следующим образом:

flask_app/templates/base.html
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">

    <title>{% block title %} {% endblock %} - FlaskApp</title>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
        <a class="navbar-brand" href="{{ url_for('hello') }}">FlaskApp</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('comments') }}">Comments</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('about') }}">About</a>
            </li>
        </ul>
        </div>
    </div>
    </nav>
    <div class="container">
        {% block content %} {% endblock %}
    </div>

    <!-- Optional JavaScript -->

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>

  </body>
</html>

Большая часть кода выше является стандартным шаблоном Bootstrap, необходимого для его использования. У вас есть несколько мета-тегов, ссылка на файл CSS Bootstrap в разделе <head>, и внизу вы имеете ссылку на дополнительный JavaScript. Выделенные части кода содержат код Jinja, объясненный на предыдущих шагах. Обратите внимание, как вы используете специфические теги и CSS-классы, чтобы сообщить Bootstrap, как отображать каждый элемент.

В теге <nav> выше у вас есть тег <a> с классом navbar-brand, который определяет ссылку бренда в навигационной панели. Внутри тега <ul class="navbar-nav"> у вас есть обычные элементы навигационной панели внутри тега <a> в теге <li>.

Чтобы узнать больше о этих тегах и CSS-классах, см. Компоненты Bootstrap.

Сохраните и закройте файл.

С запущенным сервером разработки, откройте главную страницу в вашем браузере:

http://127.0.0.1:5000/

Вы увидите страницу, похожую на следующую:

Теперь вы можете использовать компоненты Bootstrap для стилизации элементов в вашем приложении Flask во всех ваших шаблонах.

Заключение

Теперь вы знаете, как использовать HTML-шаблоны в вашем веб-приложении на Flask. Вы применяли переменные для передачи данных с сервера в шаблоны, использовали наследование шаблонов для избежания повторений, включали элементы, такие как условные операторы if и циклы for, а также связывали между собой различные страницы. Вы узнали о фильтрах для изменения текста и отображения доверенного HTML, и интегрировали Bootstrap в свое приложение.

Если вы хотите узнать больше о Flask, посетите страницу темы Flask.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-templates-in-a-flask-application