Шаг 3. Обслуживание статических файлов, добавление страниц и использование наследования шаблонов с приложением Flask
В предыдущих шагах этого руководства рассматривалось создание минимального приложения Flask с одной страницей автономного HTML. Современные веб-приложения обычно состоят из многих страниц и используют общие ресурсы, такие как файлы CSS и JavaScript, для обеспечения согласованного стиля и реакции на события.
На этом шаге вы научитесь делать следующее:
- с помощью шаблонов элементов Visual Studio быстро добавлять новые файлы различных типов с удобным стереотипным кодом (шаг 3.1);
- обрабатывать статические файлы из кода (шаг 3.2, дополнительный);
- добавлять дополнительные страницы в приложение (шаг 3–3);
- использовать наследование шаблона для создания заголовка и панели навигации, которая используется на разных страницах (шаг 3–4).
Шаг 3–1. Знакомство с шаблонами элементов
По мере разработки приложения Flask обычно добавляется гораздо больше дополнительных файлов Python, HTML, CSS и JavaScript. Для каждого типа файла (и других файлов, таких как web.config, которые могут понадобиться при развертывании) Visual Studio предоставляет удобные шаблоны элементов для начала работы.
Чтобы просмотреть доступные шаблоны, перейдите к обозревателю решений, щелкните правой кнопкой мыши папку, в которой необходимо создать элемент, выберите Добавить>Новый элемент:

Чтобы использовать шаблон, выберите нужный шаблон, укажите имя файла и нажмите кнопку ОК. При добавлении элемента таким образом автоматически добавляется файл в проект Visual Studio и отмечает изменения для системы управления версиями.
Вопрос. Как Visual Studio определяет, какой шаблон элемента предложить?
Ответ. Файл проекта Visual Studio (PYPROJ) содержит идентификатор типа проекта, который помечает его как проект Python. Visual Studio использует этот тип идентификатора для отображения шаблонов элементов, подходящих для типа проекта. Таким образом Visual Studio может предоставлять богатый набор шаблонов элементов для многих типов проектов, который не требуется отсортировывать каждый раз.
Шаг 3–2. Обработка статических файлов из приложения
В веб-приложении, созданном с помощью Python (с помощью любой платформы), файлы Python всегда выполняются на сервере веб-узла и никогда не передаются на компьютер пользователя. Другие файлы, такие как каскадные таблицы стилей и JavaScript, используются исключительно браузером, поэтому сервер узла просто доставляет их без изменений всякий раз, когда они запрашиваются. Такие файлы называются статическими файлами, Flask может доставлять их автоматически без необходимости написания кода. В HTML-файлах, например, можно ссылаться на статические файлы, используя относительный путь в проекте. Первый раздел в этом шаге служит для добавления файла CSS в существующий шаблон страницы.
Если статический файл требуется предоставлять из кода, например через реализацию конечной точки API, Flask предоставляет удобный метод, который позволяет ссылаться на файлы, используя относительные пути в папке с именем static (в корневом каталоге проекта). Во втором разделе этого шага демонстрируется работа этого метода с помощью простого статического файла данных.
В любом случае можно упорядочить файлы в static так, как вам удобно.
Использование статического файла в шаблоне

- В обозревателе решений в проекте Visual Studio щелкните папку HelloFlask правой кнопкой мыши, выберите Добавить>Новая папка и назовите папку static .
- Щелкните папку static правой кнопкой мыши и выберите Добавить>Новый элемент. В открывшемся диалоговом окне выберите шаблон Таблица стилей, назовите файл site.css и нажмите кнопку ОК. Файл site.css появится в проекте и откроется в редакторе. Структура папки должна выглядеть похоже на структуру на следующем рисунке:
- Замените все содержимое site.css следующим кодом и сохраните файл:
.message
Обслуживание статического файла из кода
Flask предоставляет функцию с именем serve_static_file , которую можно вызвать из кода для ссылки на любой файл в папке static проекта. В рамках следующей процедуры создается простая конечная точка API, которая возвращает статический файл данных.
- Создайте папку static, если это еще не сделано: в обозревателе решений в проекте Visual Studio щелкните папку HelloFlask правой кнопкой мыши, выберите Добавить>Новая папка и назовите папку static .
- В папке static создайте статический файл данных JSON с именем data.json со следующим содержимым (бессмысленный пример данных):
@app.route('/api/data') def get_data(): return app.send_static_file('data.json')
Вопрос. Существуют ли соглашения для организации статических файлов?
Ответ. Вы можете добавить другие файлы CSS, JavaScript и HTML в свою папку static любым способом. Типичный способ организации статических файлов — это создание вложенных папок fonts, scripts и content (для таблиц стилей и других файлов).
Вопрос. Как обрабатывать переменные URL-адреса и параметры запроса в API?
Шаг 3–3. Добавление страницы в приложение
Добавление еще одной страницы в приложение означает:
- добавление функции Python, которая определяет представление;
- добавление шаблона для исправления страницы;
- добавление необходимой маршрутизации в файл urls.py проекта Flask.
Следующие действия добавляются на странице «Дополнительные сведения» проекта HelloFlask и связывают эту страницу с домашней страницей:
-
В обозревателе решений щелкните правой кнопкой мыши папку templates, выберите Добавить>Новый элемент, щелкните шаблон элемента HTML-страница, назовите файл about.html и нажмите кнопку ОК.
Совет Если команда Новый элемент не появляется в меню Добавить, убедитесь, что вы остановили приложение, чтобы среда Visual Studio вышла из режима отладки.
> Home >
@app.route('/about') def about(): return render_template( "about.html", title = "About HelloFlask", content = "Example app page for Flask.")
Вопрос. Имеет ли имя функции страницы значение в Flask?
Ответ. Нет, так как URL-адреса, для которых Flask вызывает функцию для получения ответа, определяет декоратор @app.route . Разработчики обычно подбирают имя функции в соответствии с маршрутом, но такое сопоставление необязательно.
Шаг 3–4. Использование наследования шаблона для создания заголовка и навигационной панели
Вместо создания явных навигационных ссылок на каждой странице современные веб-приложения обычно используют заголовок фирменной символики и панель навигации, которая предоставляет самые важные ссылки на страницы, всплывающие меню и т. д. Чтобы обеспечить согласованность приложения, на всех страницах необходимо использовать одинаковые заголовок и панель навигации, однако при этом в каждом шаблоне страницы не должен повторяться один и тот же код. Вместо этого необходимо определить общие компоненты всех страниц в одном месте.
Система шаблонов Flask (по умолчанию Jinja) предоставляет два способа повторного использования определенных элементов в нескольких шаблонах: включение и наследование.
- Включение. Это другие шаблоны страниц, которые вставляются в определенное место в ссылочном шаблоне, используя синтаксис %> . Кроме того, можно использовать переменную, если необходимо динамически изменять путь в коде. Включение обычно используется в тексте страницы для извлечения общего шаблона в определенном расположении на странице.
- Наследование. В начале шаблона страницы используется %> для определения общего базового шаблона, на основе которого затем создается ссылочный шаблон. Наследование обычно используется для определения общих макета, панели навигации и других структур для страниц приложения, так что ссылочным шаблонам необходимо только добавлять или изменять определенные области базового шаблона, называемые блоками.
В обоих случаях относится к папке templates приложения ( ../ или ./ также разрешены).
Базовый шаблон отделяет блоки с помощью тегов %> и . Если ссылающийся на него шаблон использует теги с тем же именем блока, содержимое его блока переопределяет содержимое базового шаблона.
Далее демонстрируется наследование:
-
В папке templates приложения создайте HTML-файл (с помощью пункта контекстного меню Добавить>Новый элемент или Добавить>HTML-страница) с именем layout.html и замените его содержимое приведенным ниже кодом. Вы увидите, что этот шаблон содержит блок под названием content, который должен быть заменен для всех ссылающихся страниц:
> "
.navbar < background-color: lightslategray; font-size: 1em; font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; color: white; padding: 8px 5px 8px 5px; >.navbar a < text-decoration: none; color: inherit; >.navbar-brand < font-size: 1.2em; font-weight: 600; >.navbar-item < font-variant: small-caps; margin-left: 30px; >.body-content

Следующие шаги
Изучить тему подробнее можно с помощью следующих ресурсов:
- Сведения о дополнительных возможностях шаблонов Jinja, таких как поток управления, см. в документации по конструктору шаблонов Jinja (jinja.pocoo.org).
- Дополнительные сведения об использовании url_for см. в разделе url_for в документации по объекту приложения Flask (flask.pocoo.org).
- Исходный код, используемый в руководстве, на сайте GitHub: Microsoft/python-sample-vs-learning-flask
#6 Шаблоны во Flask
До этого момента HTML-строки записывались прямо в функцию представления. Это нормально в демонстрационных целях, но неприемлемо при создании реальных приложений. Большинство современных веб-страниц достаточно длинные и состоят из множества динамических элементов. Вместо того чтобы использовать огромные блоки HTML-кода прямо в функциях (с чем еще и неудобно будет работать), применяются шаблоны.
Шаблоны
Шаблон — это всего лишь текстовый файл с HTML-кодом и дополнительными элементами разметки, которые обозначают динамический контент. Последний станет известен в момент запроса. Процесс, во время которого динамическая разметка заменяется, и генерируется статическая HTML-страница, называется отрисовкой (или рендерингом) шаблона. Во Flask есть встроенный движок шаблонов Jinja, который и занимается тем, что конвертирует шаблон в статический HTML-файл.
Jinja — один из самых мощных и популярных движков для обработки шаблонов для языка Python. Он должен быть известен пользователям Django. Но стоит понимать, что Flask и Jinja – два разных пакета, и они могут использоваться отдельно.
Отрисовка шаблонов с помощью render_template()
По умолчанию, Flask ищет шаблоны в подкаталоге templates внутри папки приложения. Это поведение можно изменить, передав аргумент template_folder конструктору Flask во время создания экземпляра приложения.
Этот код меняет расположение шаблонов по умолчанию на папку jinja_templates внутри папки приложения.
app = Flask(__name__, template_folder="jinja_templates")
Сейчас в этом нет смысла, поэтому пока стоит продолжать использовать папку templates для хранения шаблонов.
Создаем новую папку templates внутри папки приложения flask_app . В templates — файл index.html со следующим кодом:
html lang="en"> head> meta charset="UTF-8"> title>Titletitle> head> body> p>Name: >p> body> html>
Стоит обратить внимание, что в «базовом» HTML-шаблоне есть динамический компонент > . Переменная name внутри фигурных скобок представляет собой переменную, значение которой будет определено во время отрисовки шаблона. В качестве примера можно написать, что значением name будет Jerry . Тогда после рендеринга шаблона выйдет следующий код.
html lang="en"> head> meta charset="UTF-8"> title>Titletitle> head> body> p>Name: Jerryp> body> html>
Flask предоставляет функцию rended_template для отрисовки шаблонов. Она интегрирует Jinja во Flask. Чтобы отрисовать шаблон, нужно вызвать rended_template() с именем шаблона и данными, которые должны быть в шаблоне в виде аргументов-ключевых слов. Аргументы-ключевые слова, которые передаются шаблонам, известны как контекст шаблона. Следующий код показывает, как отрисовать шаблон index.html с помощью render_template() .
from flask import Flask, request, render_template app = Flask(__name__) @app.route('/') def index(): return render_template('index.html', name='Jerry') #.
Важно обратить внимание, что name в name=’Jerry’ ссылается на переменную, упомянутую в шаблоне index.html .
Если сейчас зайти на https://localhost:5000/ , выйдет следующий ответ:

Если render_template() нужно передать много аргументов, можно не разделять их запятыми ( , ), а создать словарь и использовать оператор ** , чтобы передать аргументы-ключевые слова функции. Например:
@app.route('/') def index(): name, age, profession = "Jerry", 24, 'Programmer' template_context = dict(name=name, age=age, profession=profession) return render_template('index.html', **template_context)
Шаблон index.html теперь имеет доступ к трем переменным шаблона: name , age и profession .
Что случится, если не определить контекст шаблона?
Ничего не случится, не будет ни предупреждений, ни исключений. Jinja отрисует шаблон как обычно, а на местах пропусков использует пустые строки. Чтобы увидеть это поведение, необходимо изменить функцию представления index() следующим образом:
#. @app.route('/') def index(): return render_template('index.html') #.
Теперь при открытии https://localhost:5000/ выйдет следующий ответ:
html lang="en"> head> meta charset="UTF-8"> title>Titletitle> head> body> p>Name: p> body> html>
Сейчас должна сложиться картина того, как используются шаблоны во Flask, а в следующем разделе речь пойдет о том, как рендерить их в консоли.
Отрисовка шаблонов в консоли
Для тестирования рендерить шаблоны можно и в консоли. Это просто и не требует создания нескольких файлов. Для начала нужно запустить Python и импортировать класс Template из пакета jinja2 следующим образом.
>>> from jinja2 import Template
Для создания объекта Templates нужно передать содержимое шаблона в виде строки.
>>> t = Template("Name: >")
Чтобы отрендерить шаблон, нужно вызвать метод render() объекта Template вместе с данными аргументами-ключевыми словами
>>> t.render(name='Jerry') 'Name: Jerry'
В следующем уроке речь пойдет о шаблонизаторе Jinja.
Шаблоны в приложении Flask
В данной статье я буду практиковаться в использовании шаблонов.
В Flask вы можете использовать язык шаблонов Jinja для рендеринга HTML‑шаблонов. Шаблон — это файл, который может содержать как фиксированное, так и динамическое содержимое. Когда пользователь запрашивает что-то из вашего приложения (например, страницу индекса или страницу входа в систему), Jinja позволяет вам отвечать шаблоном HTML, в котором вы можете использовать многие функции, недоступные в стандартном HTML, такие как переменные, операторы if, циклы for, фильтры и механизм наследования шаблонов. Эти функции позволяют эффективно писать простые в обслуживании HTML‑страницы. Jinja также автоматически экранирует HTML для предотвращения Cross-Site Scripting (XSS) атак с использованием сценариев сайта.
1. Визуализация шаблона и использование переменных
Создав просто веб-приложение на Flask, я решила попробовать использование шаблонов. Для этого, я создала файл app2.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 ищет шаблоны в каталоге templates, который называется шаблонами, поэтому имя важно. Для этого выполним следующую команду, чтобы создать каталог шаблонов:
mkdir templates
Затем откроем файл с именем index.html и добавим следующий HTML код:
FlaskApp Hello World!
Welcome to FlaskApp!
Здесь мы устанавливаем заголовок, добавляем Hello World! сообщение в виде заголовка h1 и создаем сообщение Welcome to FlaskApp! как заголовок h2. Далее запускаем наше приложение. (как это сделать говорилось выше)
Оставим сервер запущенным и откроем файл app2.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 для редактирования. Отредактируем файл, чтобы он выглядел следующим образом:
FlaskApp Hello World!
Welcome to FlaskApp!
>

Мы добавили заголовок h2 со специальным разделителем > для печати значения переменной utc_dt. Откроем браузер и перейдём на главную страницу:
Теперь мы создали страницу индекса с шаблоном HTML в приложении Flask, отрисовали шаблон, передали и отобразили значение переменной. Затем мы избежим повторения кода, используя наследование шаблонов.
2. Использование механизма наследования шаблонов
На этом этапе мы создадим базовый шаблон с содержанием, которым можно будет поделиться с другими шаблонами. Мы отредактируем свой шаблон индекса, чтобы он унаследовал от базового шаблона. Затем мы создадим новую страницу, которая будет служить страницей «О приложении», где пользователи смогут найти дополнительную информацию о вашем приложении.
Для этого, создадим base.html и пропишем следующий код:
Большая часть кода в этом файле представляет собой стандартный HTML код, заголовок, некоторые стили для ссылок навигации, панель навигации с двумя ссылками, одна для страницы индекса, другая для еще не созданной страницы «О программе», а также div для содержание страницы. (Ссылки пока не работают; на следующем шаге будет показано, как создавать ссылки между страницами). Однако, следующие выделенные части относятся к шаблонизатору Jinja:
• : блок, который служит заполнителем для заголовка. Позже вы будете использовать его в других шаблонах, чтобы задать собственный заголовок для каждой страницы в приложении, не переписывая каждый раз весь раздел.
• : другой блок, который будет заменен содержимым в зависимости от дочернего шаблона (шаблона, наследуемого от base.html), который заменит его.
Теперь, когда у нас есть базовый шаблон, мы можем воспользоваться им, используя наследование. Откроем файл index.html и затем заменим его содержимое следующим:
Index
Hello World!
Welcome to FlaskApp!
>
Здесь мы используем тег для наследования от шаблона base.html. Затем мы расширяем его, заменяя блок содержимого в базовом шаблоне тем, что находится внутри блока содержимого в предыдущем блоке кода.
Этот блок содержимого содержит тег h1 с текстовым индексом внутри основной надписи, который, в свою очередь, заменяет исходную основную надпись в шаблоне base.html текстовым индексом, так что полный заголовок становится индексом — FlaskApp. Таким образом, мы можем избежать повторения одного и того же текста дважды, поскольку он работает как заголовок страницы, так и заголовок, который появляется под панелью навигации, унаследованной от базового шаблона. Затем у нас есть еще несколько заголовков: один заголовок h1 с текстом Hello World!, заголовок h2 и заголовок h3, содержащий значение переменной utc_dt.

Наследование шаблонов дает нам возможность повторно использовать HTML код, который есть в других шаблонах (в данном случае base.html), без необходимости повторять его каждый раз, когда это необходимо. Сохраним и обновим страницу индекса в браузере. Страница будет выглядеть следующим образом:
Затем мы создаем страницу «About». Открываем файл app2.py, чтобы добавить новый маршрут и добавляем следующее:
# . @app.route('/about/') def about(): return render_template('about.html')
Здесь используется декоратор app.route() для создания функции просмотра с именем about(). В нем мы возвращаем результат вызова функции render_template() с именем файла шаблона about.html в качестве аргумента.
Откроем файл шаблона с именем about.html для редактирования и добавьте следующий код:
About
FlaskApp is a Flask web application written in Python.
Здесь мы наследуем базовый шаблон с помощью тега extends, заменяем блок содержимого базового шаблона тегом h1, который также служит заголовком страницы, и добавляем тег h3 с некоторой информацией о приложении.
Когда сервер разработки запущен, перейдем по следующему URL адресу в своем браузере:
http://127.0.0.1:5000/about

Мы создали базовый шаблон и использовали его на своей индексной странице и на странице сведений, чтобы избежать повторения кода.
3. Связывание страниц
На этом этапе мы свяжем страницы в шаблонах с помощью вспомогательной функции url_for(). Мы добавим две ссылки на панель навигации в свой базовый шаблон, одну для главной страницы и другую для страницы «About».
Сначала откроем базовый шаблон для редактирования и внесите следующие изменения:
Здесь мы используем специальную функцию url_for(), которая возвращает URL адрес функции просмотра, которую мы ему передаем. Первая ссылка ссылается на маршрут функции просмотра hello() (которая является страницей индекса). Вторая ссылка указывает на маршрут функции просмотра about(). Обратите внимание, что мы передаем имя функции просмотра, а не маршрут (/ или /about). Использование функции url_for() для создания URL адресов помогает лучше управлять URL адресами. Если мы жестко запрограммируем URL адреса, наши ссылки сломаются, если мы изменим маршруты. С url_for() мы можем редактировать маршруты и гарантировать, что ссылки будут работать должным образом. Функция url_for() также заботится о других вещах, таких как экранирование специальных символов.
Теперь перейдем на главную страницу и попробуем ссылки на панели навигации. Мы увидим, что они работают.
4. Использование условных выражений и циклов
На этом этапе мы будем использовать операторы if в своих шаблонах, чтобы управлять тем, что отображать в зависимости от определенных условий. Мы также будем использовать циклы for для просмотра списков Python и отображения каждого элемента в списке. Мы добавим новую страницу, на которой будут отображаться комментарии в виде списка. Комментарии с четным порядковым номером будут иметь синий фон, а комментарии с нечетным порядковым номером будут отображаться на сером фоне.
Сначала мы создадим маршрут для страницы комментариев. Откроем файл app2.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 в каталоге шаблонов для редактирования и добавим следующий код:
Comments
>
Здесь мы расширяем шаблон base.html и заменяем содержимое блока содержимого. Во-первых, мы используем заголовок h1, который также служит заголовком страницы.
Мы используем цикл Jinja for в строке , чтобы просмотреть каждый комментарий в списке комментариев (который сохраняется в переменной комментария). Комментарий отображается в теге (p style=»font-size: 24px» > /p) так же, как мы обычно отображаем переменную в Jinja. Мы сигнализируем о завершении цикла for с помощью ключевого слова . Это отличается от способа построения циклов for в Python, поскольку в шаблонах Jinja нет специального отступа.
Когда сервер разработки запущен, откроем браузер и перейдем на страницу комментариев:
http://127.0.0.1:5000/comments
Мы увидим следующее:
Давайте откроем файл шаблона comments.html и отредактируйте его, чтобы он выглядел следующим образом:
Comments
#>
>
С помощью этого нового редактирования мы добавили оператор if в строку . Переменная цикла — это специальная переменная Jinja, которая дает нам доступ к информации о текущем цикле. Здесь мы используем loop.index, чтобы получить индекс текущего элемента, который начинается с 1, а не с 0, как в списках Python. Оператор if здесь проверяет, использует ли индекс даже оператор %. Он проверяет остаток от деления номера индекса на 2; если остаток равен 0, это означает, что номер индекса четный, в противном случае номер индекса нечетный. Тег используется для объявления переменной с именем bg_color. Если порядковый номер четный, мы устанавливаем его на голубоватый цвет, в противном случае, если номер индекса нечетный, мы устанавливаем переменную bg_color на серый. Затем мы используем переменную bg_color, чтобы установить цвет фона для тега div, содержащего комментарий. Над текстом комментария мы используем loop.index для отображения текущего номера индекса в теге p.
Сохраним и посмотрим результат:
Кроме того, чтобы отобразить все комментарии, кроме второго, мы можем использовать оператор if с условием loop.index != 2, чтобы отфильтровать второй комментарий.
Откроем шаблон комментариев и отредактируем его, чтобы он выглядел следующим образом:
Comments
#>
>
Здесь мы используем , чтобы отображать только те комментарии, которые не имеют индекса 2, что означает все комментарии, кроме второго. Мы также используем жестко запрограммированное значение для цвета фона вместо помощника loop.cycle(), чтобы упростить задачу, а остальное не изменяется. Мы завершаем оператор if, используя . Обновим страницу комментариев, и мы увидим, что второй комментарий не отображается.
Теперь нам нужно добавить ссылку, которая переводит пользователей на страницу комментариев на панели навигации. Откроем базовый шаблон для редактирования и изменим содержимое тега nav, добавив к нему новую ссылку a:
Здесь мы используем помощник url_for() для ссылки на функцию просмотра comments(). Теперь на панели навигации будет новая ссылка, которая ведет на страницу комментариев.
5. Использование фильтров
На этом этапе мы узнаем, как использовать фильтры Jinja в своих шаблонах.
Сначала мы преобразуем комментарии на странице комментариев в верхний регистр. Откроем для редактирования шаблон comments.html и отредактируем его, чтобы он выглядел следующим образом:
Comments
#>
>
Здесь мы расширяем шаблон base.html и заменяем содержимое блока содержимого. Во-первых, мы используем заголовок h1, который также служит заголовком страницы.
Мы используем цикл Jinja for в строке , чтобы просмотреть каждый комментарий в списке комментариев (который сохраняется в переменной комментария). Комментарий отображается в теге ((p style = font-size: 24px > /p)) так же, как мы обычно отображаем переменную в Jinja. Мы сигнализируем о завершении цикла for с помощью ключевого слова . Это отличается от способа построения циклов for в Python, поскольку в шаблонах Jinja нет специального отступа.
Когда сервер разработки запущен, откроем браузер и перейдем на страницу комментариев:
http://127.0.0.1:5000/comments
Фильтры также могут принимать аргументы в круглых скобках. Чтобы продемонстрировать это, воспользуемся фильтром объединения, чтобы объединить все комментарии в списке комментариев.
Откроем шаблон комментариев и отредактируем его, чтобы он выглядел следующим образом:
Comments
#>
>
>
Здесь мы добавили теги hr и div, где мы объединяем все комментарии в списке комментариев с помощью фильтра join(). Обновим страницу комментариев, и мы увидим страницу, подобную следующей:
Как видите, список comments отображается с комментариями, разделенными вертикальной чертой, которую мы передали фильтру join().
Другой важный фильтр — это безопасный фильтр, который позволяет отображать доверенный HTML код в браузере. Для его реализации откроем шаблон комментариев и отредактируем его, чтобы он выглядел следующим образом:
Comments
#>
>
COMMENTS
» >>
«) >>
#>
>
» >>
«) >>
Здесь мы добавили значение h1 COMMENTS/h1 и изменили аргумент соединения на тег hr. Обновим страницу комментариев, и мы увидите страницу, подобную следующей:
Чтобы отобразить HTML теги выше, откроем файл шаблона комментариев и добавим безопасный фильтр:
Comments
#>
>
COMMENTS
» | safe >>
«) | safe >>
#>
>
» | safe >>
«) | safe >>
Мы можем видеть, что мы также можем объединить фильтры в цепочку, как в строке p>hr. Каждый фильтр применяется к результату предыдущей фильтрации. Обновим страницу комментариев, и мы увидим, что теги HTML теперь отображаются должным образом:
6 — интеграция Bootstrap
Сейчас мы узнаем, как использовать набор инструментов Bootstrap для стилизации нашего приложения. Добавим панель навигации Bootstrap в базовый шаблон, которая будет отображаться на всех страницах, унаследованных от базового шаблона.
Чтобы использовать Bootstrap, нужно добавить его в базовый шаблон, чтобы мы могли использовать его во всех других шаблонах. Откроем свой шаблон base.html для редактирования и запишем:
Большая часть приведенного выше кода — это шаблон Bootstrap, необходимый для его использования. У нас есть несколько метатегов, ссылка на файл CSS Bootstrap в разделе head, а внизу у нас есть ссылка на необязательный JavaScript. Выделенные части кода содержат код Jinja, объясненный в предыдущих шагах.
Обратите внимание, как мы используем определенные теги и классы CSS, чтобы указать Bootstrap, как отображать каждый элемент.
В теге nav выше у нас есть тег a с классом navbar-brand, который определяет ссылку бренда на панели навигации. Внутри тега ul у нас есть обычные элементы панели навигации внутри тега a в теге li.
Когда сервер разработки запущен, откроем страницу индекса в своем браузере:
http://127.0.0.1:5000/
Мы увидим страницу, похожую на следующую:
Теперь мы знаем, как использовать HTML шаблоны в своем веб-приложении Flask. Мы использовали переменные для передачи данных с сервера в шаблоны, чтобы избежать повторения HTML кода мы использовали наследование шаблонов, встроили такие элементы, как условные выражения if и циклы for, а также ссылки между разными страницами. Мы узнали о фильтрах для изменения текста и отображения надежного HTML, а также интегрировали Bootstrap в свое приложение.
Катерина Черняк
Привет,меня зовут Катя если кто не знает.Я училась в МАОУСОШ №25 теперь учусь в ВШЭУ. Очень странная и потешная девочка,которая увлекается всем подряд.Обожаю читать и смотреть фильмы .Вроде все,такая же простая как и все из нас.
Мега-Учебник Flask, Часть 2: Шаблоны
Это вторая статья в серии, где я описываю свой опыт написания веб-приложения на Python с использованием микрофреймворка Flask.
Цель данного руководства — разработать довольно функциональное приложение-микроблог, которое я за полным отсутствием оригинальности решил назвать microblog .
Оглавление
Краткое повторение
Если вы следовали инструкциям в первой части, то у вас должно быть полностью работающее, но еще очень простое приложение с такой файловой структурой:
microblog\ flask\ app\ static\ templates\ __init__.py views.py tmp\ run.py
Для запуска приложения вы запускаете скрипт run.py, затем открываете url http://localhost:5000 в вашем браузере.
Мы продолжим с того момента, где мы остановились, так что вам следует убедиться, что вышеупомянутое приложение правильно установлено и работает.
Зачем нам нужны шаблоны
Рассмотрим то, как мы можем расширить наше маленькое приложение.
Мы хотим, чтобы на главной странице нашего приложения микроблогов был заголовок, который приветствует вошедшего в систему пользователя, что весьма стандартно для приложений такого рода. Пока что игнорируем тот факт, что у нас нет пользователей в приложении, я предоставлю решение этой проблемы в нужный момент.
Простым средством вывода большого и красивого заголовка было бы сменить нашу функцию представлений на выдачу html, примерно так:
from app import app @app.route('/') @app.route('/index') def index(): user = < 'nickname': 'Miguel' ># выдуманный пользователь return ''' Home Page Hello, ''' + user['nickname'] + '''
'''
Попробуйте посмотреть как выглядит приложение в вашем браузере.
Пока у нас нет поддержки пользователей, тем не менее, я обратился к использованию прототипов модели пользователя, которые иногда называют фальшивыми или мнимыми прототипами. Это позволяет нам сконцентрироваться на некоторых аспектах нашего приложения, зависящих от частей системы, которые еще не были написаны.
Надеюсь вы согласитесь со мной, что решение выше очень уродливое. Представьте насколько сложным станет код, если вы должны возвращать громоздкую HTML страницу с большим количеством динамического содержимого. И что если вам нужно сменить макет вашего веб-сайта в большом приложении с множеством представлений, которые возвращают HTML напрямую? Это очевидно не масштабируемое решение.
Шаблоны спешат на помощь
Не задумывались ли вы о том, что если бы вы могли держать раздельно логику вашего приложения и макет, или представление ваших страниц было бы организовано куда лучше? Вы даже можете нанять веб-дизайнера, чтобы создать сногсшибательный сайт в то время, пока вы программируете его [сайта] поведение при помощи Python. Шаблоны помогут осуществить это разделение.
Напишем наш первый шаблон (файл app/templates/index.html ):
> - microblog Hello, >!
Как видно выше, мы просто написали стандартную HTML страничку, но с одним лишь отличием: плейсхолдеры для динамического содержимого заключены в секции >
Теперь рассмотрим использование шаблона в нашей функции представления (файл app/views.py ):
from flask import render_template from app import app @app.route('/') @app.route('/index') def index(): user = < 'nickname': 'Miguel' ># выдуманный пользователь return render_template("index.html", title = 'Home', user = user)
Запустите приложение на данном этапе, чтобы посмотреть как работают шаблоны. Если в вашем браузере отрисована страница, то вы можете сравнить ее исходный код с оригинальным шаблоном.
Чтобы отдать страницу, нам нужно импортировать из Flask новую функцию под названием render_template. Эта функция принимает имя шаблона и список переменных аргументов шаблона, а возвращает готовый шаблон с замененными аргументами.
Под капотом: функция render_template вызывает шаблонизатор Jinja2, который является частью фреймворка Flask. Jinja2 заменяет блоки > на соответствующие им значения, переданные как аргументы шаблона.
Управляющие операторы в шаблонах
Шаблоны Jinja2 помимо прочего поддерживают управляющие операторы, переданные внутри блоков . Давайте добавим оператор if в наш шаблон (файл app/templates/index.html ):
> - microblog Welcome to microblog Hello, >!
Теперь наш шаблон слегка поумнел. Если мы забудем определить название страницы в функции представления, то взамен исключения шаблон предоставит нам собственное название. Вы спокойно можете удалить аргумент заголовка из вызова render_template в нашей функции представления, чтобы увидеть как работает оператор if.
Циклы в шаблонах
Вошедший в наше приложение пользователь наверняка захочет увидеть недавние записи от пользователей из его контакт-листа на главной странице, давайте посмотрим как же это сделать.
В начале, мы провернем трюк, чтобы создать несколько ненастоящих пользователей и несколько записей для отображения (файл app/views.py ):
def index(): user = < 'nickname': 'Miguel' ># выдуманный пользователь posts = [ # список выдуманных постов < 'author': < 'nickname': 'John' >, 'body': 'Beautiful day in Portland!' >, < 'author': < 'nickname': 'Susan' >, 'body': 'The Avengers movie was so cool!' > ] return render_template("index.html", title = 'Home', user = user, posts = posts)
Чтобы отобразить пользовательские записи мы используем список, где у каждого элемента будут поля автор и основная часть. Когда мы доберемся до осуществления реальной базы данных мы сохраним эти имена полей, так что мы можем разрабатывать и тестировать наш шаблон, используя ненастоящие объекты, не беспокоясь об их обновлении, когда мы перейдем на базу данных.
Со стороны шаблона мы должны решить новую проблему. Имеющийся список может содержать любое количество элементов и нужно решить сколько сообщений будет представлено. Шаблон не может сделать никаких предположений о количестве сообщений, поэтому он должен быть готов отобразить столько сообщений, сколько пошлет представление.
Посмотрим как сделать это, используя управляющую структуру (файл app/templates/index.html ):
> - microblog microblog Hi, >!
> says: >
Не так уж и трудно, правда? Проверим приложение и обязательно проверим добавление нового содержимого в список записей.
Наследование шаблонов
Мы охватим еще одну тему, прежде чем закончить на сегодня.
Нашему приложению микроблогов необходима навигационная панель с несколькими ссылками сверху страницы. Там будут ссылки на редактирование вашего профиля, выход и т.д.
Мы можем добавить навигационную панель в наш шаблон index.html , но, как только наше приложение разрастется, нам понадобится больше шаблонов, и навигационную панель нужно будет скопировать в каждый из них. Тогда вы должны держать все эти копии одинаковыми. Это может стать трудоемкой задачей, если у вас много шаблонов.
Вместо этого мы можем использовать наследование в шаблонах Jinja2, которое позволяет нам переместить части макета страницы в общий для всех базовый шаблон, из которого все остальные шаблоны будут наследоваться.
Теперь определим базовый шаблон, который включает в себя навигационную панель, а также логику заголовка, которую мы реализовали ранее (файл app/templates/base.html ):
> - microblog microblog Microblog: Home
В этом шаблоне мы использовали управляющий оператор block для определения места, куда могут быть вставлены дочерние шаблоны. Блокам даются уникальные имена.
Теперь осталось изменить наш index.html так, чтобы он наследовался от base.html (файл app/templates/index.html ):
Hi, >!
> says: >
Теперь только шаблон base.html отвечает за общую структуру страницы. Мы убрали те элементы отсюда и оставили только часть с содержимым. Блок extends устанавливает наследственную связь между двумя шаблонами, таким образом Jinja2 знает: если нам нужно отдать index.html , то нужно включить его в base.html . Два шаблона имеют совпадающие операторы block с именем content , именно поэтому Jinja2 знает как cкомбинировать два шаблона в один. Когда мы будем писать новые шаблоны, то также станем создавать их как расширения base.html
Заключительные слова
Если вы хотите сэкономить время, то приложение микроблога в текущей стадии доступно здесь:
Скачать microblog-0.2.zip
Учтите, что zip файл не содержит в себе виртуального окружения flask. Создайте его сами, следуя инструкциям в первой части, после этого вы сможете запустить приложение.
В следующей части серии мы взглянем на формы. Надеюсь увидимся.