Вы уже прошли путь создания оригинальных интерактивных презентаций «Выбери своё приключение», преодолели испытания «Только для волшебников» и разобрались с веб-формами в предыдущих статьях. Теперь пришло время достать наши магические палочки для последнего трюка и завершить создание приложения.
В этом заключительном уроке мы добавим в наше Flask-приложение новую функцию, которая позволит аудитории голосовать с помощью веб-браузера на своих ноутбуках… или смартфонах. Мы напишем код для отслеживания голосов аудитории через веб-браузеры с использованием WebSocket-соединений. Новая система голосования через браузер дополнит существующую SMS-систему, когда сигнал сотовой связи работает нестабильно.
Засучите рукава своего плаща и приготовьтесь написать ещё немного Python-кода, чтобы завершить создание приложения для интерактивных презентаций.
Если вы следовали первой и второй частям этого цикла, то уже настроили все зависимости и подключения к базе данных, которые понадобятся для этой части урока.
Если вы ещё не читали первую или вторую часть — ничего страшного. Вот краткий обзор инструментов и библиотек, которые мы использовали для создания приложения:
— PostgreSQL для постоянного хранения данных. PostgreSQL обеспечивает работу режима «Только для волшебников», сохраняя данные аутентификации и презентаций.
— Redis и redis-py для временного хранения. Redis хранит результаты голосования, поэтому убедитесь, что процесс redis-server запущен в фоновом режиме во время разработки.
— Драйвер psycopg2 для подключения к PostgreSQL. Psycopg2 продолжает обеспечивать связь между веб-приложением и базой данных.
— Flask-SocketIO для создания и работы с WebSocket в приложении Flask.
— Flask-Login для аутентификации. В первой части мы настроили Flask-Login для защиты страниц «Только для волшебников».
— Flask-WTF для обработки веб-форм. В этой статье мы создадим множество новых страниц, поэтому будем активно использовать Flask-WTF в следующих разделах.
Вы можете догнать нас, проработав код из первой и второй частей, или просто клонируйте репозиторий CYOA Presentations с тегом tutorial-step-5. Вот команды для клонирования репозитория, чтобы быстро войти в курс дела:
Если вам нужна пошаговая инструкция по созданию виртуального окружения, повторной установке зависимостей из файла `requirements.txt`, экспорту переменных окружения для проекта и синхронизации таблиц базы данных, подробные объяснения для каждого из этих шагов есть в первой части урока. Обратите внимание, что если вы допустите опечатку в процессе работы над этой статьёй, вы можете сравнить свою версию с тегом tutorial-step-6.
Нам нужно создать новые экраны «Только для волшебников», чтобы настроить голосование через веб-браузер, когда мы захотим включить его для презентаций. Обратите внимание, что нам не обязательно включать голосование через браузер — мы можем продолжать использовать только SMS. Однако новые экраны просто дают нам возможность заменить или дополнить SMS-голосование, что особенно полезно, если сотовая связь в помещении работает нестабильно. После написания кода в этом разделе и запуска сервера разработки новые административные экраны должны выглядеть так, как показано на скриншотах ниже.
При создании презентации появится возможность управлять голосованием через веб-браузер, как показано выше. Ссылка «Управление вариантами» ведёт волшебника на новый экран, где можно редактировать, удалять или создавать решения.
Решения можно создавать и сохранять с помощью простой формы, как показано ниже.
Давайте перейдём к новому коду, который нужно написать, чтобы превратить скриншоты выше в часть работающего приложения. Откройте существующий файл `cyoa/models.py` в любимом редакторе. Мы добавим первую выделенную строку в модель Presentation, которая представляет внешний ключ к новой модели Decision. Модель Decision будет хранить слаги веб-страниц, которые позволят участникам аудитории голосовать за решение. Добавьте новую строку в Presentation и создайте новую модель Decision, как показано ниже.
Новый код моделей выше позволяет сохранять и управлять решениями для голосования через браузер, которые могут быть связаны с конкретными презентациями.
Далее нужно обновить файл `cyoa/forms.py`, добавив новый класс DecisionForm. Внутри `cyoa/forms.py` добавьте следующий новый класс формы, как показано ниже.
Класс `DecisionForm` используется для создания и редактирования решений через пользовательский интерфейс. Мы добавили базовую валидацию, чтобы гарантировать правильный ввод URL-слагов пользователем.
Следующий файл, который критически важен для запуска голосования через браузер, — это `cyoa/wizard_views.py`. Изменения, которые мы внесём в этот файл, позволят нам изменять решения в презентациях, чтобы пользователи могли голосовать через браузер только за те варианты, которые мы для них создали. Во второй части урока мы добавили заглушки функций в этот файл `wizard_views.py`, зная, что развернём их в этой статье. Убедитесь, что удалили ключевое слово `pass` из тела этих функций и вставили выделенный код, показанный ниже.
Мы добавили код для отображения, создания, редактирования и удаления решений в системе. Это стандартные операции для административного интерфейса, которые ожидает любой уважающий себя волшебник.
Хорошо, это весь Python-код, который нам нужен на данный момент для новых экранов «Только для волшебников». Теперь нужно создать несколько новых шаблонов для генерации HTML-кода наших экранов решений. Создайте новый файл `cyoa/templates/wizard/decisions.html` со следующей разметкой.
Приведённая выше разметка шаблона перебирает существующие решения и отображает название каждого из них, а также первый и второй пути развития истории вместе с опциями удаления или просмотра веб-страницы решения. Если для выбранной презентации не возвращается решений из базы данных, появится простое объяснение: «Голосование через браузер для [название презентации] не включено». Для работы голосования через браузер должны быть созданы точки решений в пользовательском интерфейсе.
Также нужен шаблонный файл для создания новых решений и редактирования существующих. Создайте файл `cyoa/templates/wizard/decision.html` и вставьте следующую разметку. Убедитесь, что назвали этот файл без буквы «s» в конце слова «decision», чтобы не перезаписать предыдущий шаблон, который мы только что создали.
С помощью приведённого выше шаблона у нас есть возможность создавать и редактировать решения. Шаблон генерируется с отправкой формы либо для создания нового решения, если была нажата кнопка «Новое решение», либо для редактирования существующего решения.
Наконец, пришло время протестировать наш новый код! Создайте новую таблицу базы данных `Decision`, выполнив следующую команду в корневом каталоге проекта.
Теперь запустите сервер разработки с помощью следующей команды, как мы делали в предыдущих статьях.
Перейдите по адресу http://localhost:5001/wizard, чтобы ознакомиться с текущей версией нашего приложения.
Пока всё хорошо. Войдите в систему, используя стандартные учётные данные: имя пользователя «gandalf» и пароль «thegrey», которые были созданы в первой части урока.
Если в вашем приложении уже есть презентации, нажмите на ссылку «Управление вариантами» для одной из них или создайте новую презентацию и затем нажмите на ссылку. К сожалению, после нажатия на «Управление вариантами» мы внезапно получим следующую страницу с ошибкой…
Ой. Что происходит? Похоже, новое отношение внешнего ключа в таблице `Presentation` вызывает ошибку базы данных. Хотя мы создали новую таблицу `Decision` с помощью команды `syncdb`, она не создала столбец внешнего ключа в таблице `Presentation`.
Как исправить эту проблему? Нам нужно убедиться, что в таблице `Presentation` есть соответствующий столбец в базе данных. Для этого мы можем:
— Использовать библиотеку для выполнения миграции схемы на основе наших обновлённых моделей SQLAlchemy
— Добавить столбец вручную в базу данных с помощью оператора ALTER TABLE
— Удалить и заново создать базу данных и синхронизировать таблицы.
Для простоты в этой статье мы воспользуемся третьим методом — удалением и повторным созданием базы данных. Обратите внимание, что, к сожалению, существующие волшебники и презентации в базе данных будут удалены, поэтому мы также пройдём процесс их повторного создания.
Остановите процесс сервера разработки с помощью `Ctrl-C` и выполните следующие команды для повторного создания базы данных PostgreSQL.
Нам также нужно создать нового пользователя-волшебника в базе данных, так как предыдущий был удалён.
С нашей новой моделью Decision давайте завершим этот урок, добавив функциональность голосования через браузер. Откройте файл `cyoa/views.py` и обновите следующие выделенные строки.
Приведённый выше код создаёт два новых маршрута для отображения вариантов голосования и решений, созданных в интерфейсе волшебника. Эти страницы решений позволяют участнику аудитории голосовать, нажимая одну из двух кнопок на странице и оставаясь на странице голосования. Эти голоса подсчитываются так же, как и SMS-голосования, пока пользователь находится на странице.
Активное WebSocket-соединение увеличивает счётчик голосов за этот вариант в Redis, а когда пользователь покидает страницу, WebSocket-соединение закрывается и значение в Redis для этого варианта уменьшается. Однако у голосования через браузер есть один недостаток: WebSocket-соединение может не сразу распознаваться как закрытое. Может пройти несколько секунд, прежде чем соединение будет закрыто и счётчик голосов уменьшится.
Нам осталось выполнить ещё пару шагов для завершения функциональности голосования через браузер. Измените файл `cyoa/websockets.py`, добавив выделенный код, показанный ниже.
Приведённый выше код обрабатывает WebSocket-соединения и определяет выбор пользователя.
Есть одно небольшое изменение на странице решений волшебника, которое облегчит нам жизнь. Мы хотим иметь возможность сразу просматривать решение после его создания. Для этого отредактируйте файл `cyoa/templates/decisions.html` и обновите следующую единственную выделенную строку.
Это одно изменение в файле `decisions.html` позволяет волшебнику просматривать созданное им решение, открывая новое окно браузера с решением.
Нам осталось создать ещё один шаблонный файл! Создайте новый шаблон с именем `cyoa/templates/web_vote.html` со следующим содержимым.
Давайте запустим наше приложение в последний раз, чтобы увидеть голосование через браузер в действии.
Запустите сервер разработки с помощью следующей команды, как мы делали в предыдущих статьях.
Создайте новую презентацию с указанными ниже данными или на основе уже созданной вами презентации.
Затем создайте точку решения с помощью нового кода, написанного в этом уроке. Это решение позволит аудитории голосовать через веб-браузер. Создайте решение, как показано ниже, и сохраните его.
Нажмите на ссылку в крайнем правом столбце, чтобы просмотреть новое решение.
Выберите один из двух вариантов на экране, и ваш голос будет учтён вместе с любыми другими голосами через браузер и SMS.
Вы голосуете за этот вариант через WebSocket, просто оставаясь на этой странице! Этот тип голосования очень полезен, когда сотовая связь в помещении не работает или вы проводите презентацию за границей, где у многих нет активного тарифного плана, как, например, на PyCon 2015 в Канаде.
Теперь у нас есть возможность голосовать как через SMS, так и через веб-браузер в наших интерактивных презентациях «Выбери своё приключение»! Если у вас возникли проблемы, которые вы не смогли решить, помните, что есть тег tutorial-step-6, содержащий готовый код для этой статьи.
Наш режим Волшебника завершён. Теперь у нас гораздо больше контроля над презентациями и новый механизм голосования аудитории через веб-браузеры в дополнение к SMS. С нашими боевыми улучшениями мы готовы использовать их в живой технической презентации. На самом деле, это тот самый код, который Кейт Хеддлстон и я использовали для докладов «Выбери своё приключение при развёртывании WSGI» на PyCon 2015.
Дайте знать, какие новые истории для интерактивных презентаций «Выбери своё приключение» вы придумали, или откройте пулл-реквест для улучшения кодовой базы. Свяжитесь со мной через:
— Email: makai@twilio.com
— GitHub: Следите за makaimc для обновлений репозитория
— Twitter: @mattmakai