Использование шаблонов помогает упростить многие задачи разработчиков. Многие новички, которые уже немного изучили фреймворк Flask, уже умеют записывать HTML строки в функции представления. Но при создании реальных программ такой подход не совсем верен. Он используется для демонстрации возможностей фреймворка и при обучении, но не в реальной работе. Дело в том, что подавляющее число современных веб-приложений является довольно длинным, и в их состав входит большое количество динамических элементов. Вместо того, чтобы записывать большие HTML-блоки непосредственно в функциях, можно сделать эту задачу проще с помощью шаблонов. Сегодня мы и поговорим о них более подробно.
Что такое шаблон во Flask?
Шаблон – это текстовый файл, содержащий HTML-код и дополнительные элементы разметки для обозначения динамического контента. О том, какой последний, становится известно в момент запроса. Процесс создания статической HTML-страницы на основе динамической разметки называется рендерингом шаблона.
Flask содержит встроенный движок Jinja, отвечающий за конвертацию шаблона в статический HTML. Этот движок многие считают одним из самых мощных и популярных. Пользователи Django уже наслышаны о нем. Тем не менее, Flask и Jinja могут использоваться отдельно.
Использование render_template для отрисовки шаблонов
Если не изменять стандартные настройки, Flask осуществляет поиск шаблонов внутри папки приложения в подкаталоге templates. Но возможно изменение такого поведения, использовав аргумент template_folder в конструкторе Flask в процессе создания экземпляра приложения.
С помощью этого кода можно изменить расположение шаблонов по умолчанию на папку jinja_templates внутри папки приложения.
app = Flask(__name__, template_folder="jinja_templates")
Сейчас в этом нет никакой необходимости. Следовательно, для хранения шаблонов будет продолжать использовать папку templates.
Давайте создадим новую папку templates внутри программы. И в эту папку добавим файл index.html, в котором содержится следующий код.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>Name: {{ name }}</p> </body> </html>
Следует учитывать то, что в стандартном шаблоне имеется динамический компонент
{{ name }}. Такая переменная, заключенная в фигурные скобки, являет собой переменную, значение которой определяется во время отрисовки шаблона. В качестве примера можно привести значение Jerry в качестве имени. Тогда после того, как произойдет рендеринг шаблона, получится такой код.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>Name: Jerry</p> </body> </html>
С помощью функции rended_template Flask отрисовывает шаблоны. Она осуществляет интеграцию 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 на ту переменную, которая описана в шаблоне index.html.
Если зайти на сайт http://localhost:5000, то появится ответ Name: Jerry.
Если осуществлять передачу большого количества аргументов, то можно просто создать словарь в совокупности с оператором ** для передачи основных ключевых слов функции. Это поможет значительно упростить код, сделать его более читаемым и сэкономить время на написании программы.
Вот пример кода, который реализует эту функцию.
@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)
Этот шаблон получает доступ к переменным name, age, profession.
Что произойдет, если не определять контекст шаблона? В принципе, ничего особенного. Не будет ни предупреждений, ни исключений. Jinja выполнит стандартную отрисовку шаблона, а на местах пропусков просто будут пустые строки. Чтобы увидеть это поведение, надо изменить функцию index() так, как показано в этом фрагменте кода.
#... @app.route('/') def index(): return render_template('index.html') #...
Теперь, когда открывается страница http://localhost:5000/, ответ будет следующим.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>Name: </p> </body> </html>
Вот, как применяются шаблоны во Flask. Теперь мы поговорим, каким образом осуществляется их рендеринг в консоли.
Отрисовка шаблонов в консоли
Рендеринг шаблонов может осуществляться и в консоли. Как правило, это делается для тестирования приложения. Преимущество такого подхода в том, что это просто, и не требуется создание дополнительных файлов. Сперва нужно включить интерпретатор Python и импортировать класс Template из пакета jinja2.
>>> from jinja2 import Template
Чтобы создать объект класса Templates, необходимо написать строку, которая передает содержимое шаблона.
>>> t = Template("Name: {{ name }}")
Для рендеринга шаблона, необходимо воспользоваться методом render() объекта Template вместе с аргументами-ключевыми словами.
Работа с шаблонами на примерах
Итак, что такое шаблоны? Предположим, необходимо создать программу для создания микроблогов. В этом приложении должен быть заголовок, который приветствует пользователя. И, предположим, надо создать вымышленного пользователя, который реализуется с помощью mock-объектов. Для этого используется классический словарь Python.
user = {'username': 'Miguel'}
Такой метод разработки полезен тем, что позволяет сосредоточиться исключительно на одной части программы, не задумываясь о том, какие другие части системы, которые еще не работают. Предположим, нужно создать домашнюю страницу приложения, которая бы стабильно работала вне зависимости от того, есть ли система пользователя, или нет. Именно поэтому мы и создаем отдельный объект пользователя.
Функция просмотра в программе возвращает простую строку. Теперь давайте попробуем расширить ее в полную страницу.
from app import app @app.route('/') @app.route('/index') def index(): user = {'username': 'miguel'} return ''' <html> <head> <title>Home Page - Microblog</title> </head> <body> <h1>Hello, ''' + user['username'] + '''!</h1> </body> </html>'''
После того, как мы запустим этот код, и перейдем по адресу работы приложения (localhost:5000/index), то появится надпись «Hello, Miguel!».
Вообще, такой метод – не идеален. Предположим, появятся сообщения от постоянно изменяющихся пользователей. В этом случае, код будет очень сложным. Также в программе будет большое количество функций просмотра, взаимосвязанных с другими URL. Представьте, что в один момент понадобится изменить макет веб-приложения. В этом случае, в каждом представлении придется выполнять обновление HTML.
Этот вариант не будет масштабироваться по мере того, как у приложения будут появляться новые пользователи, будет увеличиваться количество записей.
С помощью шаблонов можно решить эту проблему. Например, если понадобится нанять дизайнера, который бы создал сайт, внешний вид которого обеспечивал хорошую конверсию, то тогда логика этого приложения может быть закодирована в виде шаблонов, и дизайнер просто пропишет свою часть кода, которая бы встраивалась в этот шаблон.
Шаблоны по функциональности напоминают обычные веб-страницы, только в них содержатся изменяемые элементы, которые динамически подстраиваются под обновляющиеся задачи.
Пример готового шаблона такой:
<html> <head> <title>{{ title }} - Microblog</title> </head> <body> <h1>Hello, {{ user.username }}!</h1> </body> </html>
В целом, он очень упрощенный. Обратите внимание, что для динамического контента используются заполнители, заключенные в разделы, обозначенные фигурными скобками. Они представляют изменяемые части страницы, и их содержимое определяется исключительно тогда, когда программа выполняется.
Теперь, когда была осуществлена выгрузка презентации в шаблон HTML, упрощается функция просмотра (файл app\routes.py).
# -*- coding: utf-8 -*- from flask import render_template from app import app @app.route('/') @app.route('/index') def index(): user = {'username': 'Miguel'} return render_template('index.html', title='Home', user=user)
Согласитесь, что так значительно лучше. Собственно, рендеринг, простыми словами – это и есть преобразование шаблона в полноценную веб-страницу.
Использование условных операторов и циклов в шаблонах
Внутри блоков также можно использовать управляющие операторы. Например, так.
<html> <head> {% if title %} <title>{{ title }} - Microblog</title> {% else %} <title>Welcome to Microblog!</title> {% endif %} </head> <body> <h1>Hello, {{ user.username }}!</h1> </body> </html>
Такой шаблон адаптируется под заданные условия. Если функция просмотра не показывает пустой заголовок, то тогда предоставляется значение по умолчанию.
Также возможно использование циклов в шаблонах. Реализуется это следующим образом.
# -*- coding: utf-8 -*- from flask import render_template from app import app @app.route('/') @app.route('/index') def index(): user = {'username': 'Эльдар Рязанов'} posts = [ { 'author': {'username': 'John'}, 'body': 'Beautiful day in Portland!' }, { 'author': {'username': 'Susan'}, 'body': 'The Avengers movie was so cool!' }, { 'author': {'username': 'Ипполит'}, 'body': 'Какая гадость эта ваша заливная рыба!!' } ] return render_template('index.html', title='Home', user=user, posts=posts)