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

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

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

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

Прежде чем…

§1. Визуализация шаблона и использование переменных

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

Сначала в каталоге flask_app откройте файл с именем app.py для редактирования. Можно открыть PyCharm или свой любимый текстовый редактор, добавим следующий код в файл 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, который называется шаблонами, поэтому имя важно. Убедитесь, что вы находитесь в каталоге flask_app, и выполните следующую команду, чтобы создать каталог шаблонов:

mkdir templates

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

nano templates/index.html

Добавьте следующий HTML‑код в файл 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):

export FLASK_APP=app
export FLASK_ENV=development

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

flask run

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

http://127.0.0.1:5000/

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

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

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

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 и передали в шаблон index.html переменную с именем utc_dt со значением datetime.datetime.utcnow(), которое является текущей датой и временем в формате UTC.

Затем, чтобы отобразить значение переменной на странице индекса, откройте файл 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>

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

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

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

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

§2. Использование механизма наследования шаблонов

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

Сначала откройте новый файл с именем 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 %}: блок, который служит заполнителем для заголовка. Позже вы будете использовать его в других шаблонах, чтобы задать собственный заголовок для каждой страницы в приложении, не переписывая каждый раз весь раздел .
  • {% block content %} {% endblock %}: другой блок, который будет заменен содержимым в зависимости от дочернего шаблона (шаблона, наследуемого от base.html), который заменит его.

Теперь, когда у вас есть базовый шаблон, вы можете воспользоваться им, используя наследование. Откройте файл 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. Затем вы расширяете его, заменяя блок содержимого в базовом шаблоне тем, что находится внутри блока содержимого в предыдущем блоке кода.

Этот блок содержимого содержит тег <h1> с текстовым индексом внутри основной надписи,который, в свою очередь, заменяет исходную основную надпись в шаблоне base.html текстовым индексом, так что полный заголовок становится индексом — FlaskApp. Таким образом, вы можете избежать повторения одного и того же текста дважды, поскольку он работает как заголовок страницы, так и заголовок, который появляется под панелью навигации, унаследованной от базового шаблона.Затем у вас есть еще несколько заголовков: один заголовок <h1> с текстом Hello World!, заголовок <h2> и заголовок <h3>, содержащий значение переменной utc_dt.

Наследование шаблонов дает вам возможность повторно использовать HTML‑код, который есть в других шаблонах (в данном случае base.html), без необходимости повторять его каждый раз, когда это необходимо. Сохраните и закройте файл и обновите страницу индекса в браузере. Страница будет выглядеть следующим образом:

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

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

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

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

Откройте файл шаблона с именем 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, заменяете блок содержимого базового шаблона тегом <h1>, который также служит заголовком страницы, и добавляете тег <h3> с некоторой информацией о приложении.

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

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

http://127.0.0.1:5000/about

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

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

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

§3. Связывание страниц

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

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

<!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 для редактирования и добавьте следующий маршрут в конец файла::

# ...

@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.html в последней строке,передача переменной с именем comments, содержащей список, в файл шаблона.

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

Затем откройте новый файл 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 и заменяете содержимое блока содержимого. Во-первых, вы используете заголовок <h1>, который также служит заголовком страницы.

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

Когда сервер разработки запущен, откройте браузер и перейдите на страницу комментариев:

http://127.0.0.1:5000/comments

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

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

Откройте файл шаблона 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 %}. Переменная цикла — это специальная переменная 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 и отредактируйте его, чтобы он выглядел следующим образом::

{% 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, чтобы отфильтровать второй комментарий.

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

{% 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 %}. Сохраните и закройте файл.

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

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

<!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 и отображения каждого элемента в списке, а также узнали о специальной переменной цикла в Jinja. Далее вы будете использовать фильтры Jinja для управления отображением переменных данных.

§5. Использование фильтров

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

Сначала вы преобразуете комментарии на странице комментариев в верхний регистр. Откройте для редактирования шаблон 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 %}

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

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

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

Когда сервер разработки запущен, откройте браузер и перейдите на страницу комментариев:

http://127.0.0.1:5000/comments

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

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

{% 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>, где вы объединяете все комментарии в списке комментариев с помощью фильтра join().

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

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

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

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

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

{% 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>» и изменили аргумент соединения на тег <hr>.

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

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

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

Чтобы отобразить 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 }}<hr>. Каждый фильтр применяется к результату предыдущей фильтрации.

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

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

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

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

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

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

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

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

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

Откройте свой шаблон 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/bootstrap@5.1.0/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/bootstrap@5.1.0/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. Вы использовали переменные для передачи данных с сервера в шаблоны, чтобы избежать повторения HTML‑кода вы использовали наследование шаблонов, встроили такие элементы, как условные выражения if и циклы for, а также ссылки между разными страницами. Вы узнали о фильтрах для изменения текста и отображения надежного HTML, а также интегрировали Bootstrap в свое приложение.

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

How To Use Templates in a Flask Application

Опубликовано Вадим В. Костерин

ст. преп. кафедры ЦЭиИТ. Автор более 130 научных и учебно-методических работ. Лауреат ВДНХ (серебряная медаль).

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *