Продолжаем развивать тему микро web-фереймворка написаном на чудесном языке python, а именно, Flask.
Краткое повторение
Если вы читали предыдущую статью, должны иметь следующий проект с простой файловой структурой:
Application\ flask\ <virtualenvironmentfiles> app\ static\ templates\ __init__.py views.py tmp\ run.py
Для запуска приложения мы использовали скрипт run.py
К чему повторение?
Что бы убедиться, что у вас есть выше приведенное приложение, правильно установлено и работает.
Для чего нам нужны шаблоны?
Давайте посмотрим, как мы можем расширить наше небольшое приложение.
Как правило, на главной странице нашего блога мы хотим иметь заголовок, приветствующий вошедшего в систему пользователя, это довольно стандартное решение. Пока же мы работаем со статическими данными, чтобы понять как все устроено.
Легким вариантом для вывода будет большой заголовок (h1). Изменим нашу функцию представления, чтобы она выглядела примерно так:
from app import app @app.route('/') @app.route('/index') def index(): user={'nickname':'Miguel'}# fakeuser return''' <html> <head> <title>HomePage</title> </head> <body> <h1>Hello, '''+user['nickname']+'''</h1> </body> </html> '''
Посмотрите что получилось.
Поскольку мы еще не имеем пользователей и шаблонов, а выше представленный код может касаться некоторых аспектов нашего приложения, зависящих от частей системы, которые мы еще не построили.
Надеюсь, вы согласитесь со мной, данное решение не очень красиво.
Шаблоны на помощь
Как все хорошие веб девелоперы мы будем отделять шаблоны от логики.
Давайте напишем наш первый шаблон в данном проекте (файл app/templates/index.html ):
<html> <head> <title>{{title}} - application</title> </head> <body> <h1>Hello, {{user.nickname}}!</h1> </body> </html>
Только что мы создали простую HTMLстраницу, с отличием лишь в том, что добавили блоки {{ … }} для динамического отображения контента.
Теперь же вызовем шаблон с файла отображения:
«Вся эта структура напоминает MVC», – подумал я. Потом понял, что так и будет 🙂 т.к в документацию, только когда что то не работает или работает не так как хотелось бы.
from flask import render_template from app import app @app.route('/') @app.route('/index') def index(): user={'nickname':'Miguel'}# fakeuser return render_template("index.html", title='Home', user=user)
В коде встречаемновую для нас функцию из пакета Flask render_template.
Данная функция вызывает шаблонизатор jinja2 ,который является частью фреймворка Jinja2 заменяет блоки {{…}} соответствующими значениями, предоставляемыми в качестве аргументов шаблона.
В файле run.py дописываем конфиги:
app.config['ASSETS_DEBUG'] = True app.debug = True
Данный код корректновключаетdebug режим для отображение шаблонов Jinja2.
Управляющие конструкции Flask (Python)
Шаблонизатор Jinja2 также поддерживает управляющие конструкции в своих блоках {%…%}. Давайте попробуем изменить (file app/templates/index.html):
<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>Welcometomicroblog</title> {% endif %} </head> <body> <h1>Hello, {{user.nickname}}!</h1> </body> </html>
Теперь наш шаблон немого умнее. Если мы забываем передать параметр (в нашем случае заголовок страницы), то шаблон подставит собственный. Рекомендую проверить корректность роботы и понять что к чему. Удалить в файле представления аргумент title.
Циклы в шаблонах
В представлениитипа блог нам все же придерсяиспользовать циклы.
Для начала создадим статический массив с постами в функции представления.
def index(): user={'nickname':'Miguel'}# fakeuser posts=[# fake array of posts { 'author':{'nickname':'John'}, 'body':'BeautifuldayinPortland!' }, { 'author':{'nickname':'Susan'}, 'body':'TheAvengersmoviewassocool!' } ] returnrender_template("index.html", title='Home', user=user, posts=posts)
Для представления записей пользователей мы используем массив в котором каждый элемент имеет 2 поля автор и тело. Можно сказать, мы проектируем наш шаблон без использования базы данных, что бы потом просто когда научимся ею пользоваться, подключится и начать выводить прямо на страницу.
В шаблоне встретим и другую проблему. Массив может иметь любое количество элементов, это будет зависеть от функции вида, сколько выводить элементов.
Смотрим шаблон с использованием конструкции for ( app/templates/index.html):
<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>microblog</title> {% endif %} </head> <body> <h1>Hi, {{user.nickname}}!</h1> {% for post in posts %} <p>{{post.author.nickname}} says: <b>{{post.body}}</b></p> {% endfor %} </body> </html>
Просто, не так ли? (напоминает конструкцию foreach из php) Попробуйте и убедитесь, играя с добавлением содержания в массив.
Шаблон наследований
Последняя тема на сегодня по шаблонам.
Наше приложение должно иметь навигацию в верху страницы и пару ссылок. Например «редактировать профиль», «выход» и тому подобное.
Мы можем добавить навигацию в наш шаблон, но наше приложение растет, и мы должны иметь больше шаблонов, поэтому эту навигацию придется копировать в каждый из них.
Вместо того, чтобы дублировать, мы воспользуемся функцией наследования jinja2, которая позволит сделать один вид для общих представлений, поставив код в базовый шаблон, а все остальные будут производными. (app/templates/base.html)
<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>microblog</title> {% endif %} </head> <body> <div>Microblog: <ahref="/index">Home</a></div> <hr> {% blockcontent %}{% endblock %} </body> </html>
Данный шаблон имеет управляющую конструкцию block, для определения места вывода шаблона внутри себя. Блоки должны иметь уникальные имена.
Теперь изменим наш первоначальный шаблон:
{% extends"base.html" %} {% blockcontent %} <h1>Hi,{{user.nickname}}!</h1> {% for post in posts%} <div><p>{{post.author.nickname}}says:<b>{{post.body}}</b></p></div> {% endfor %} {% endblock %}
Поскольку сам шаблон base.html теперь будет заботиться об общей структуре, мы удалили лишние элементы из этого шаблона и оставили только ту часть содержимого, которая нам нужна.
Extends – устанавливает связь наследования межу двумя шаблонами.
Два шаблоны имеют соответствующие заявления блока с содержанием имени, и это заложено в jinja2, поэтому она знает, как объединить два в одном. Когда мы пишем новые шаблоны, также создаем их как расширения для base.html.