Miguel Grinberg
Это одиннадцатая часть Мега-Учебника Flask, в которой я расскажу вам, как заменить базовые шаблоны HTML новыми, основанными на структуре пользовательского интерфейса Bootstrap.
Под спойлером приведен список всех статей этой серии 2018 года.
- Глава 1: Привет, мир!
- Глава 2: Шаблоны
- Глава 3: Веб-формы
- Глава 4: База данных
- Глава 5: Пользовательские логины
- Глава 6: Страница профиля и аватары
- Глава 7: Обработка ошибок
- Глава 8: Подписчики, контакты и друзья
- Глава 9: Разбивка на страницы
- Глава 10: Поддержка электронной почты
- Глава 11: Реконструкция(Эта статья)
- Глава 12: Дата и время
- Глава 13: I18n и L10n
- Глава 14: Ajax
- Глава 15: Улучшение структуры приложения
- Глава 16: Полнотекстовый поиск
- Глава 17: Развертывание в Linux
- Глава 18: Развертывание на Heroku
- Глава 19: Развертывание на Docker контейнерах
- Глава 20: Магия JavaScript
- Глава 21: Уведомления пользователей
- Глава 22: Фоновые задачи
- Глава 23: Интерфейсы прикладного программирования (API)
Примечание 1: Если вы ищете старые версии данного курса, это здесь.
Примечание 2: Если вдруг Вы захотели бы выступить в поддержку моей(Мигеля) работы, или просто не имеете терпения дожидаться статьи неделю, я (Мигель Гринберг)предлагаю полную версию данного руководства(на английском языке) в виде электронной книги или видео. Для получения более подробной информации посетите learn.miguelgrinberg.com.
Вы уже некоторое время упражняетесь с моим приложением Microblog, поэтому я уверен, что вы заметили, что я не слишком старался, чтобы страницы выглядели красиво, или, лучше сказать, что я не потратил на это вообще времени. Шаблоны, которые я собрал вместе, довольно простые, с абсолютно простым стилем. Мне было важно сосредоточиться на фактической логике приложения, не отвлекаясь на хорошо выглядящие HTML и CSS.
Я уже достаточно времени фокусировался на бэкэнд-части этого приложения. Поэтому в этой главе я делаю перерыв от этого славного занятия и займусь тем, чтобы сделать приложение немного более привлекательным и внешне профессиональным.
Эта глава будет несколько отличаться от предыдущих, потому что я не буду так подробно, как обычно работать с Python, который в конце концов является основной темой этой книги. Создание привлекательных веб-страниц — это обширная тема, которая в значительной степени вовсе не связанная с веб-разработкой на Python, но я расскажу о некоторых основных принципах и идеях. О том, как подойти к задаче. И в итоге у вас также будет приложение с переработанными внешним видом для углубленного изучения.
Ссылки GitHub для этой главы: Browse, Zip, Diff.
CSS-фреймворки
Хотя вы можете утверждать, что "кодить" тяжко, ваша боль ничто по сравнению с тем, что испытывают веб-дизайнеры, создающие шаблоны, которые должны иметь приятный и лаконичный вид для всего списка веб-браузеров. В последние годы стало получше! Но еще есть странные ошибки или причуды в некоторых браузерах, которые сильно усложняют задачу проектирования веб-страниц таким образом, что бы они отображались везде и всегда одинаково хорошо. Это еще сложнее, если вам также нужно выполнить настройки отображения с учетом ограничений экранов для планшетов и смартфонов.
Если вы, как и я, являетесь разработчиком, который просто хочет получить хороший вид веб-страниц, но не имеете времени или интереса, чтобы изучать глубины механизмов для достижения этой эффективности путем написания RAW HTML и CSS, то единственным практическим решением является использование CSS framework
для упрощения этой задачи. Вы потеряете некоторую творческую свободу, принимая этот путь, но с другой стороны, ваши веб-страницы будут прилично выглядеть во всех браузерах при минимуме приложенных усилий. framework CSS предоставляет коллекцию классов CSS высокого уровня с готовыми стилями для распространенных типов элементов пользовательского интерфейса. Большинство из этих фреймворков также предоставляют JavaScript дополнения для решений, которые не могут быть сделаны строго с HTML и CSS.
Знакомство с Bootstrap
Одной из самых популярных платформ CSS является Bootstrap, созданный Twitter. Если вы хотите увидеть своими глазами страницы, которые могут быть разработаны с этой платформой в документации есть несколько примеров.
Вот некоторые из преимуществ использования Bootstrap для стиля веб-страниц:
- Похожие отображения во всех основных веб-браузерах
- Обработка настольных, планшетных и телефонных размеров экрана
- Настраиваемые макеты
- Красиво стилизованные навигационные панели, формы, кнопки, оповещения, всплывающие окна и т.д.
Самый простой способ использования Bootstrap — просто импортировать файл Bootstrap.min.CSS
в базовый шаблон. Можно либо загрузить копию этого файла и добавить его в проект, либо импортировать непосредственно из CDN. После этого вы можете начать использовать классы CSS общего назначения, которые он предоставляет, в соответствии с документацией, что очень удобно. Можно импортировать файл Bootstrap.min.js
, содержащий JavaScript-код фреймворка, что позволяет использовать самые продвинутые функции.
К счастью, есть расширение Flask называется Flask-Bootstrap. Предоставляет готовый к использованию базовый шаблон, который включает в себя платформу Bootstrap. Давайте установим это расширение:
(venv) $ pip install flask-bootstrap
Использование Flask-Bootstrap
Flask-Bootstrap должен быть инициализирован, как и большинство других расширений Flask:
app/__init__.py: Инициализация Flask-Bootstrap.
# ...
from flask_bootstrap import Bootstrap
app = Flask(__name__)
# ...
bootstrap = Bootstrap(app)
При инициализации расширения шаблон bootstrap/base.html становится доступным в других шаблонах приложения по тегу extends
.
Как вы помните, я уже использую тег extends
с моим собственным базовым шаблоном, который позволяет мне формировать общие части страницы в одном месте. Шаблон base.html определяет панель навигации, которая включает несколько ссылок, а также экспортирует блок content
. Все остальные шаблоны в моем приложении наследуют элементы базового шаблона и предоставляют блоку content
основное содержимое страницы.
Итак, как же мне следует использовать базовый шаблон Bootstrap? Идея состоит в том, чтобы использовать трехуровневую иерархию вместо двух. Шаблон bootstrap/base.html предоставляет базовую структуру страницы на основе фреймворка Bootstrap. Этот шаблон экспортирует несколько блоков для производных шаблонов, таких как title
, navbar
и content
(см. Полный список блоков здесь). Я собираюсь изменить свой base.html-шаблон, чтобы использовать в нем решения из bootstrap/base.html и обеспечить реализации для заголовков(title
), навигационных блоков(navbar
) и блоков контента(content
). В свою очередь, base.html будет экспортировать собственный блок app_content
для своих производных шаблонов определяющих содержимое страницы.
Ниже видно, как выглядит base.html после модификации его в наследника базового шаблона Bootstrap. Обратите внимание, что эта структура не включает весь HTML для панели навигации, но вы можете найти полную реализацию на GitHub или загрузить код для этой главы.
app/templates/base.html: Переработанный базовый шаблон.
{% extends 'bootstrap/base.html' %}
{% block title %}
{% if title %}{{ title }} - Microblog{% else %}Welcome to Microblog{% endif %}
{% endblock %}
{% block navbar %}
<nav class="navbar navbar-default">
... здесь должна быть навигационная панель (см. полный код на GitHub) ...
</nav>
{% endblock %}
{% block content %}
<div class="container">
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-info" role="alert">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
{# содержимое приложения которое должно быть предоставлено в блоке app_content #}
{% block app_content %}{% endblock %}
</div>
{% endblock %}
Здесь видно, как я использую шаблон из bootstrap/base.html, за которым следуют три блока, которые реализуют заголовок страницы, панель навигации и содержимое страницы соответственно.
Блок title
определяет текст, который будет использоваться в качестве заголовка страницы, с тегами <title>
. Для этого блока я просто переместил логику, которая находилась внутри тега <title>
в исходном базовом шаблоне.
Блок navbar
является необязательным блоком, который обычно используется в качестве панели навигации. Для этого блока я адаптировал пример из документации на панель навигации Bootstrap, так что он включает в себя брендинг сайта, а затем ссылки Home и Explore. После чего я добавил ссылки профиля, входа или выхода из системы, выровненные с правой границей страницы. Как я уже упоминал выше, я опустил HTML в приведенном выше примере, но вы можете получить полный шаблон base.html из пакета загрузки для этой главы.
Наконец, в блоке content
я определяю контейнер верхнего уровня, и внутри него у меня есть логика, которая отображает свернутые сообщения, которые теперь будут отображаться в стиле оповещений Bootstrap. За ним следует новый блок app_content
, который определяется так, чтобы производные шаблоны могли определять свой собственный контент.
Исходная версия всех шаблонов страниц определяла их содержимое в блоке с именем content
. Как вы видели выше, блок с именем content
используется из Flask-Bootstrap, поэтому я переименовал свой content
-блок как app_content
. После чего, все мои шаблоны необходимо исправить, чтобы использовать app_content
в качестве своего content
-блока(содержимого). В качестве примера: так выглядит модифицированная версия шаблона 404.html:
app/templates/404.html: Переработанный шаблон ошибки 404.
{% extends "base.html" %}
{% block app_content %}
<h1>File Not Found</h1>
<p><a href="{{ url_for('index') }}">Back</a></p>
{% endblock %}
Bootstrap визуализация форм
Область, в которой Flask-Bootstrap делает фантастическую работу, — это использование форм. Вместо того, чтобы устанавливать поля формы одно за другим, Flask-Bootstrap пользуется макросом, который принимает объект формы Flask-WTF в качестве аргумента и отображает полную форму с использованием стилей Bootstrap.
Ниже вы можете увидеть переработанный шаблон register.html в качестве примера:
app/templates/register.html: Шаблон регистрации пользователя.
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h1>Register</h1>
<div class="row">
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
</div>
{% endblock %}
Разве это не здорово? import
в верхней части примера работает аналогично импорту Python. Только в составе шаблона. Эта команда добавляет макрос wtf.quick_form()
, который в одной строке кода отображает полную форму, включая поддержку ошибок проверки отображения, и все в стиле Bootstrap.
Еще раз повторюсь, я не собираюсь показывать вам все изменения, которые я сделал для других форм в приложении. Но все эти изменения сделаны в том самом коде, который вы можете скачать или проверить на GitHub.
Визуализация сообщений в блогах
Логика представления, которая отображает отдельные сообщения в блоге, была абстрагирована в подшаблон под названием _post.html. Все, что мне нужно сделать с этим шаблоном, — это внести небольшие корректировки, чтобы он выглядел в стиле Bootstrap.
app/templates/_post.html: Переработанный суб-шаблон сообщений.
<table class="table table-hover">
<tr>
<td width="70px">
<a href="{{ url_for('user', username=post.author.username) }}">
<img src="{{ post.author.avatar(70) }}" />
</a>
</td>
<td>
<a href="{{ url_for('user', username=post.author.username) }}">
{{ post.author.username }}
</a>
says:
<br>
{{ post.body }}
</td>
</tr>
</table>
Отображение ссылок на страницы ленты сообщений
Связывание страниц — это еще одна область, где Bootstrap обеспечивает прямую поддержку. Для этого я просто обратился еще раз к документации Bootstrap и адаптировал один из своих примеров. Вот как они выглядят на странице index.html:
app/templates/index.html: Переработанный вариант многостраничного отображения сообщений.
...
<nav aria-label="...">
<ul class="pager">
<li class="previous{% if not prev_url %} disabled{% endif %}">
<a href="{{ prev_url or '#' }}">
<span aria-hidden="true">←</span> Newer posts
</a>
</li>
<li class="next{% if not next_url %} disabled{% endif %}">
<a href="{{ next_url or '#' }}">
Older posts <span aria-hidden="true">→</span>
</a>
</li>
</ul>
</nav>
Обратите внимание, что в этой реализации вместо того, чтобы скрывать следующую или предыдущую ссылку, когда в этом направлении больше нет контента, я применяю disabled
состояние, которое сделает ссылку недоступной.
Я не буду показывать все здесь, но подобное изменение должно быть применено к user.html. Пакет загрузки для этой главы включает и эти изменения.
До и после
Чтобы обновить приложение, загрузите zip-файл для этой главы и аккуратненько сравните и обновите свои шаблоны.
Ниже приведены несколько снимков экрана до и после, чтобы продемонстрировать трансформацию. Имейте в виду, что эти изменение были достигнуты без изменений логики приложений!
P.S. От переводчика
На первом скрине приглашение имеет стандартную надпись 'Please log in to access this page.'
Это умолчание модуля flask-login. Если вас эта надпись по каким то причинам не устраивает, то ее можно заменить собственной. Для этого требуется определить свойство login_message
экземпляра класса LoginManager
. Однако, следует помнить, что если вы добавляете кириллические символы в модуль, то необходимо, что бы первая строка устанавливала требуемую кодировку.
app/__init__.py: Доработанный вариант
.
# -*- coding: utf-8 -*-
…
login = LoginManager(app)
login.login_view = 'login'
login.login_message = "Пожалуйста, войдите, чтобы открыть эту страницу." # <--
я добавил эту строку
...