Jinja ‒ шаблонизатор для Python. Использование Jinja2 во Flask
Шаблонизатор (template engine) ‒ это такая программа, которая, читая данные из одного источника (файла-шаблона), находит в нем специальные конструкции и согласно определенным правилам заменяет их на данные из другого источника. На выходе вы получаете готовый документ, где уже нет никаких "переменых" и "неизвестных", все данные определены и "жестко вшиты". Для генерации html-страниц существует много разных шаблонизаторов.
Фреймворк Flask включает в себя Jinja2 ‒ шаблонизатор, для которого в шаблонах используются элементы синтаксиса языка Python.
Когда мы вызываем функцию render_template
и передаем ей имя файла, помимо прочего в дело вступает и Jinja-движок, пропуская через себя содержимое файла.
В наших двух html-файлах много общего. Будет правильным вынести это общее в отдельный файл, а в местах, где у каждого свое, подставлять это свое из других файлов.
Изменим файл base.html следующим образом:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}Главная страница{% endblock %} | Основы биологии </title> </head> <body> {% block content %} <h1>О сайте "Основы биологии"</h1> <p>Описание в разработке</p> {% endblock %} </body> </html>
Мы обрамили часть содержимого тайтла и основной контент документа специальными командами-тегами. В браузере, перезагрузив страницу, вы не увидите изменений. Более того, открыв там исходный код (Ctrl + U), заметите, что эти команды были подчистую вырезаны.
Файл plants.html изменим сильнее:
{% extends 'base.html' %} {% block title %}Растения{% endblock %} {% block content %} <h1>Растения</h1> <p>Общая характеристика растений</p> {% endblock %}
С помощью команды extends
реализуется наследование шаблонов. Родителем здесь выступает base.html. Файл plants.html наследует все его содержимое, то есть контент base.html вставляется в plants.html как есть. Но то, что находится внутри обозначенных в plants.html блоков, заменяется собой то, что находится в таких же блоках в base.html.
Часто внутри родительского файла в block-контейнерах нет содержимого. Следуя такой логике, файл base.html должен выглядеть так:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}{% endblock %} | Основы биологии </title> </head> <body> {% block content %}{% endblock %} </body> </html>
При этом для главной страницы сайта мы должны были бы создать другой файл, например, index.html, и заполнить его по аналогии с plants.html.
Обратим внимание, что если родительский файл содержит block-контейнер, который не используется в дочернем, то это не вызывает ошибки. Как и наоборот ‒ дочерний может содержать контейнер, которого нет в родительском. Подобное может иметь место при более сложном наследовании: файл выступает базовым шаблоном для нескольких других или дочерний файл в свою очередь является родителем для другого.
Когда в проекте используется база данных, то программа, которую мы пишем на Python, берет из нее данные и при вызове функции rander_template
передает их в шаблон. Эти данные вставляются в указанных местах (между тегами HTML, внутри значений атрибутов HTML), которые как могут находиться внутри block-контейнеров, так и быть за их пределами.
При использовании базы данных сайт обычно имеет не так много шаблонов. Однако в нашем случае каждый шаблон ‒ это страница сайта. С помощью фреймворка Flask мы лишь облегчаем себе обслуживание сайта, убирая повторяющийся код в общий шаблон.
Такой вариант сайта удобнее для случая, когда:
- Не планируется предоставлять пользователям возможность регистрироваться на сайте и наполнять его контентом.
- Вы предпочитаете редактировать страницы сайта на локальном компьютере в привычной среде разработки или текстовом редакторе, а не через веб-интерфейс (который надо еще разработать) в браузере или какой-либо sql-браузер (менее удобно).
Также у вас не будет таких возможностей, как извлечение определенных данных из всего множества статей, их обобщение, сортировка и т. п. Для небольших, выглядящих статично со стороны пользователей, сайтов обычно этого не требуется.
Вернемся к тому, что при вызове rander_template()
в функцию можно передавать не только имя файла html-шаблона, а также данные для его заполнения в соответствующих местах. Будем передавать путь страницы. Перед этим в файл base.html перед тегом </head>
добавим следующую строку:
<link rel="canonical" href="https://biology.su{{ address }}">
Здесь в двойных фигурных скобках указывается имя аргумента, который будет передаваться в функцию render_template
. Значение аргумента будет подставлено вместо всей конструкции {{ address }}
. Если в этот момент обновить страницу сайта, несмотря на то, что аргумент не передавался, ошибки не будет. Фреймворк уберет конструкцию. Однако если с переменной выполняются какие-то действия (что-то извлекается, складывается с чем-то), то возникнет ошибка.
В файле программы добавим соответствующий аргумент render_template()
в одном из представлений:
@app.route('/plants') def page(): return render_template('plants.html', address='/plants')
Количество дополнительных именованных аргументов может быть любым.