Использование шаблонов страниц сайта

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

from flask import Flask
 
app = Flask(__name__)
 
@app.route("/")
def index():
    return '''<!DOCTYPE html>
<html>
<head>
         <title></title>
</head>
<body>
 
</body>
</html>'''
 
 
@app.route("/about")
def about():
    return "<h1>Про Flask</h1>"
 
if __name__ == "__main__":
    app.run(debug=True)

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

Для работы с шаблонами Flask использует стандартный модуль Jinja (если вы не знаете что это такое и как происходит обработка шаблонов, то смотрите занятия по этой ссылке).

Чтобы воспользоваться шаблонизатором во Flask нужно импортировать его элемент  render_template:

from flask import Flask, render_template

и, затем, в обработчике index вызвать его:

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

Следующий вопрос: где расположить шаблон 'index.html', чтобы он был найден и загружен модулем Flask. Существует следующее простое соглашение: по умолчанию все шаблоны берутся из подкаталога templates, относительно рабочего каталога программы (или соответствующем подкаталоге пакета). Так мы и сделаем. Разместим в этом подкаталоге файл index.html со следующим содержимым:

<!DOCTYPE html>
<html>
<head>
         <title>Главная страница сайта</title>
</head>
<body>
<h1>Главная страница сайта</h1>
</body>
</html>

Обратите внимание, для корректного отображения кириллицы все шаблоны рекомендуется сохранять в кодировке utf-8. Тем более, что сам Python, начиная с версии 3, по умолчанию использует юникод.

Запустим программу и при переходе на главную страницу увидим отображение нашего шаблона в браузере:

По аналогии создадим такой же шаблон about.html и также будем загружать его при обращении по URL /about:

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

Теперь, посещая эту страницу, пользователь увидит:

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

Передача шаблонам параметров

Я много раз произносил слово «шаблон», но что оно означает? Если посмотреть на файлы index.html или about.html, то это просто текст, который загружается и отдается браузеру по соответствующему запросу. Все так, но в этих же файлах можно прописать конструкции для отображения информации, например, из БД. Давайте для начала сделаем так, чтобы на каждой странице был свой заголовок, переданный ей через параметр title. Это можно сделать так:

<!DOCTYPE html>
<html>
<head>
         <title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
</body>
</html>

А в обработчике указать этот параметр:

return render_template('index.html', title="Про Flask")

Все, теперь вместо title будет подставлена строка «Про Flask». Удобно, правда? Вот в этом и есть роль шаблонов: они описывают структуру страницы, а ее наполнение происходит динамически в самой программе.

Но какие вообще конструкции можно использовать в шаблонах? Как я уже отмечал, модуль Flask использует шаблонизатор Jinja и шаблоны строятся по его правилам. Если вы не знаете как работать с шаблонами, то под этим видео увидите ссылку на этот курс.

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

<ul>
{% for m in menu %}
<li>{{m}}</li>
{% endfor %}
</ul>

А в программе добавить список и передать его шаблону:

menu = ["Установка", "Первое приложение", "Обратная связь"]
 
@app.route("/")
def index():
    return render_template('index.html', title="Про Flask", menu = menu)

При обновлении страницы увидим следующее:

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

{% if title %}
         <title>Про Flask - {{title}}</title>
{% else %}
         <title>Про Flask</title>
{% endif %}

И то же самое для тега h1:

{% if title -%}
<h1>{{title}}</h1>
{% else -%}
<h1>Про Flask</h1>
{% endif %}

Теперь в обработчике можно не указывать параметр title, тогда будет отображаться строка «Про Flask», а иначе, подставляться другой заголовок, причем во вкладке браузеры будем видеть «Про Flask - <заколовок>». Например, пропишем такой же шаблон для about.html и в обработчике добавим:

def about():
    return render_template('about.html', title = "О сайте", menu = menu)

В результате, вид страницы будет такой:

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

<!DOCTYPE html>
<html>
<head>
{% block title -%}
{% if title %}
         <title>Про Flask - {{title}}</title>
{% else %}
         <title>Про Flask</title>
{% endif %}
{% endblock %}
</head>
<body>
{% block content -%}
         {%- block mainmenu -%}
<ul>
         {% for m in menu -%}
<li>{{m}}</li>
         {% endfor -%}
</ul>
         {% endblock mainmenu -%}
         {% if title -%}
<h1>{{title}}</h1>
         {% else -%}
<h1>Про Flask</h1>
         {% endif -%}
{% endblock -%}
</body>
</html>

А в дочерних расширим этот базовый шаблон:

- для index.html:

{% extends 'base.html' %}
 
{% block content %}
{{ super() }}
Содержимое главной страницы
{% endblock %}

- для about.html:

{% extends 'base.html' %}
 
{% block content %}
{{ super() }}
Содержимое страницы "о сайте"
{% endblock %}

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

Видео по теме