Как написать web приложение на python

Dash — библиотека для языка Python с открытым исходным кодом, предназначенная для создания реактивных веб-приложений. Она была загружена на GitHub два года назад в тестовом режиме. Команда разработчиков Dash решила оставить этот прототип в сети, однако продолжила вести работу над проектом уже вне платформы GitHub. Благодаря обратной связи от банков и лабораторий, а также от команд, работающих с анализом данных, разработчики определили курс развития библиотеки. Сегодня уже представлена первая публичная версия Dash, которая подходит как для корпоративных клиентов, так для клиентов премиум-класса продукции Plotly. Библиотека может быть использована как с Plotly, так и самостоятельно.

В настоящее время Dash можно загрузить, используя диспетчер пакетов Python, с помощью команды pip install dash. Dash распространяется с открытым исходным кодом и под лицензией MIT. На официальном сайте вы сможете ознакомиться с руководством по библиотеке, и на GitHub вы найдёте исходный код.

Dash — библиотека пользовательского интерфейса для создания аналитических веб-приложений. Она будет полезна для тех, кто использует Python для анализа и исследования данных, визуализации, моделирования и отчётности.

Dash значительно упрощает создание GUI (графических пользовательских интерфейсов) для анализа данных. Вот пример приложения на Dash из 43 строк кода, который связывает выпадающее меню с графиком D3.js. Когда пользователь выбирает значение в выпадающем списке, код динамически экспортирует данные из Google Finance в Pandas DataFrame:

Код Dash является декларативным и реактивным, что упрощает создание сложных приложений, содержащих множество интерактивных элементов. Вот пример с 5 входными данными, 3 — выходными и с перекрёстной фильтрацией. Это приложение было написано на Python, и в нём всего лишь 160 строк кода:

Приложение на Dash с несколькими входными и выходными данным.

Для каждого элемента приложения можно задать собственные параметры размера, расположения, цвета и шрифта. Приложения на Dash создаются и публикуются в Сети, поэтому к ним можно применить всё, на что способен CSS. Ниже иллюстрируется пример тонко настраиваемого интерактивного приложения отчётности на Dash, выполненного в стиле отчёта финансовой организации Goldman Sachs.

Тонко настраиваемое приложение Dash, созданное в стиле отчёта финансовой организации Goldman Sachs.

Вам не нужно писать какой-либо код на JavaScript или HTML, когда ваше приложение на Dash запущено в веб-браузере. Dash предоставляет богатый набор интерактивных веб-компонентов.

import dash_core_components as dcc
dcc.Slider(value=4, min=-10, max=20, step=0.5,
           labels={-5: '-5 Degrees', 0: '0', 10: '10 Degrees'})

Пример простого ползунка на Dash

Dash предоставляет простой реактивный декоратор для привязки вашего кода анализа данных к пользовательскому интерфейсу Dash.

@dash_app.callback(Output('graph-id', 'figure'),
                   [Input('slider-id', 'value')])
def your_data_analysis_function(new_slider_value):
    new_figure = your_compute_figure_function(new_slider_value)
    return new_figure

Когда изменяется входной элемент (например, при выборе элемента в выпадающем списке или при передвижении ползунка), декоратор Dash предоставляет вашему коду Python новое входное значение.

Ваша функция Python может выполнять различные действия с новым входным значением: может фильтровать объект DataFrame библиотеки Pandas, выполнять SQL-запрос, запускать симуляцию, выполнять вычисления или запускать тестирование. Dash рассчитывает, что ваша функция вернёт новое свойство для какого-нибудь элемента пользовательского интерфейса, будь то новый график, новая таблица или новый текст.

В качестве примера ниже представлено приложение на Dash, которое обновляет текстовый элемент при взаимодействии с графиком. Код приложения фильтрует данные в Pandas DataFrame на основе выбранной точки:

Приложение ниже отображает метаинформацию о лекарственных веществах при наведении курсора на точки в графике. Код приложения также добавляет строки в таблицу, когда появляются новые компоненты в выпадающем списке.

Благодаря этим двум разделениям между компонентами Python и реактивными функциональными декораторами, Dash разграничивает все технологии и протоколы, необходимые для создания интерактивного веб-приложения. Dash достаточно прост, чтобы привязать пользовательский интерфейс к коду Python за один вечер.

Архитектура

Flask и React.js

Приложения на Dash — веб-серверы, которые запускают Flask и связывают пакеты JSON через HTTP-запросы. Интерфейс Dash формирует компоненты, используя React.js.

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

React.js также великолепен, например, мы переписали всю нашу веб-платформу и наш онлайн-редактор диаграмм с помощью React. Но есть кое-что, что действительно радует насчёт React — активный и талантливый состав сообщества разработчиков, который опубликовал тысячи высококачественных компонентов, начиная с выпадающих списков и слайдеров, заканчивая календарями и интерактивными таблицами. И всё это публикуется с открытым исходным кодом!

Dash использует мощь Flask и React, подстраивая их под работу с Python для специалистов по анализу и обработке данных, которые могут не быть экспертами в области веб-разработки.

От React.js к компонентам Python

Компоненты Dash — это классы Python, которые кодируют свойства и значения конкретного компонента React и упорядочиваются как JSON. Dash предоставляет набор инструментов для лёгкой упаковки компонентов React в вид компонентов, которые могут быть использованы в Dash. Этот набор инструментов использует динамическое программирования для автоматического создания классов Python из аннотированного свойства React — propTypes. На выходе классы Python, которые представляют компоненты Dash, являются удобными для пользователя, так как они имеют автоматическую проверку аргументов, строк документации и прочее.

Вот пример динамически сгенерированной проверки ошибочного аргумента:

>>> import dash_core_components as dcc
>>> dcc.Dropdown(valu=3)
Ошибка: неизвестный ключевой аргумент `valu`
Допустимые аргументы: id, className, disabled, multi, options, placeholder, value

Пример динамически создаваемых строк документации:

 >>> help(dcc.Dropdown)
class Dropdown(dash.development.base_component.Component)
 |  Компонент выпадающего списка.
 |  Компонент выпадающего списка служит для выбора одного или более
 |  элементов.
 |  значения и названия элементов выпадающего списка определяются в `options`
 |  свойство и выбранный элемент(ы) определяются свойством `value`.
 |
 |  используйте выпадающий список, только если у вас много вариантов выбора (больше 5), или
 | когда вы ограничены пространством. В противном случае вы можете использовать переключатели или чекбоксы,
 |  Которые покажут сразу все элементы пользователю.
 |
 |  Аргументы ключевых слов:
 |  - id (строка; необязательный)
 |  - className (строка; необязательный)
 |  - disabled (логический тип; необязательный): если true, выбор блокируется
 |  - multi (логический тип; необязательный): если true, пользователь может выбрать несколько значений
 |  - options (список; необязательный)
 |  - placeholder (строка; необязательный): серый текст по умолчанию, если ничего не выбрано
 |  - value (строка | список; необязательный): значение поля ввода. Если `multi` false (по умолчанию),
 |  то value — строка, соответствующая своим значениям,
 |  указанным в свойстве `options`. Если `multi` — true, то
 |  можно выбрать сразу несколько значений, а `value` — 
 |  массив элементов со значениями, соответствующими в свойстве 
 |  `options`.
 |
 |  Доступные события: 'change

Полный набор HTML-тегов (наподобие div, img, table) также обрабатывается с помощью React, а их классы Python доступны через библиотеку dash_html_component. Основной набор интерактивных компонентов, таких как Dropdown, Graph, Slider, будет поддерживаться командой Dash через dash_core_components. Обе библиотеки используют стандартный набор инструментальных средств React-to-Dash с открытым исходным кодом, который вы могли бы использовать при необходимости написания своей собственной библиотеки компонентов.

Ваше приложение автоматически не привязывается к библиотеке компонентов Dash. Библиотека компонентов импортируется отдельно от основной библиотеки Dash. С помощью набора инструментальных средств React-to-Dash можно легко записать или перенести компонент React.js в класс Python, который можно использовать в приложении Dash. На официальном сайте вы найдёте руководство по созданию собственных компонентов или можете попросить команду разработчиков Dash написать их для вас.

Многопользовательские приложения

Свойства приложения на Dash хранятся в интерфейсе (в браузере). Это позволяет использовать приложения, написанные с использованием Dash, в многопользовательском режиме: может быть открыто несколько независимых друг от друга сессий, в которых действия одних пользователей не будут влиять на данные других пользователей. Код приложения на Dash является функциональным: он может считывать значения из глобальных свойств Python, но не может вносить в них изменения. Этот функциональный подход можно легко обосновать и протестировать — это просто входные и выходные данные без каких-либо побочных эффектов или свойств.

CSS и стили

CSS и стили по умолчанию хранятся вне базовой библиотеки, чтобы сохранить принцип модульности и независимого управления версиями и чтобы подтолкнуть разработчиков Dash-приложений настраивать вид своих приложений. Команда Dash разместила руководство по основным стилям.

Визуализация данных

Библиотека Dash поставляется с компонентом Graph, который отвечает за отображение диаграмм с помощью Plotly.js. Библиотека Plotly.js отлично подходит к Dash (отличное дополнение), так как она декларативна и имеет открытый исходный код. Кроме того, она поддерживает полный спектр научных, финансовых и деловых диаграмм. Она создана на основе D3.js (для диаграмм типографического качества и экспорта векторных изображений) и WebGL (для высокопроизводительной визуализации).

В библиотеке Dash элемент Graph использует тот же синтаксис, что и библиотека Plotly.py с открытым исходным кодом, что даёт вам возможность легко переключаться между ними. Компонент Graph подключается к системе событий Plotly.js, позволяя авторам писать приложения, которые реагируют на наведение курсора, щелчки и выбор определённых точек на графиках Plotly.

Репозитории с открытым исходным кодом

  • бэкенд библиотеки Dash;
  • фронтенд библиотеки Dash;
  • библиотека основных компонентов Dash;
  • библиотека HTML-компонентов Dash;
  • набор инструментальных средств React-to-Dash;
  • документация и руководство по Dash;
  • Plotly.js —JavaScript- библиотека, используемая Dash.

Прототипирование

Dash — это новая библиотека в среде Python, однако концепции и идеи, на которых строится Dash, существуют в течение десятилетий на разных языках и в разных приложениях.

Если вы разбираетесь в Excel, значит, вам будет проще разобраться и в Dash. Ведь они оба используют «реактивную» модель программирования. В Excel ячейки с выходными данными обновляются автоматически при изменении параметров ячеек с входными данными. Любая ячейка может быть входной или выходной или и тем, и другим. В ячейках с входными данными нет информации о том, какие ячейки с выходными данными зависят от них, что упрощает добавление новых ячеек с выходными данными или позволяет связать несколько ячеек. Вот пример Excel-приложения:

Можно провести аналогию для Dash. Вместо ячеек у нас есть богатый спектр веб-компонентов, таких как ползунки, поля ввода, выпадающие списки и графики. Вместо написания сценария Excel или VBA мы пишем код Python. Ниже представлено то же самое приложение, но в этот раз оно написано на Dash:

app.layout = html.Div([
    html.Label('Hours per Day'),
    dcc.Slider(id='hours', value=5, min=0, max=24, step=1),
    html.Label('Rate'),
    dcc.Input(id='rate', value=2, type='number'),
    html.Label('Amount per Day'),
    html.Div(id='amount'),
    html.Label('Amount per Week'),
    html.Div(id='amount-per-week')
])
@app.callback(Output('amount', 'children'),
              [Input('hours', 'value'), Input('rate', 'value')])
def compute_amount(hours, rate):
    return float(hours) * float(rate)
@app.callback(Output('amount-per-week', 'children'),
              [Input('amount', 'children')])
def compute_amount(amount):
    return float(amount) * 7

Некоторым разработчикам нравится этот пример, потому что Excel по-прежнему занимает доминирующее положение даже в технических вычислениях и в финансовой математике. Я не думаю, что доминирующее положение Excel — это технический вопрос. В конце концов, есть легионы программистов, которые изучили нюансы Excel, VBA и даже SQL.

Более того, таблицы Excel легче распространять, чем программы на Python, а ячейки Excel легче редактировать, чем аргументы командной строки.

Тем не менее, моделирование в Excel имеет известные ограничения: эти таблицы часто становятся слишком большими или уязвимыми, чтобы переводить их на производственный уровень, проводить экспертную оценку или тестировать и поддерживать. Вам ведь знаком случай со знаменитой опечаткой в 2013 году?

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

Фреймворк Shiny

Если вы программируете на R, вам повезло. Shiny — это реактивный фреймворк для создания веб-приложений на чистом R, и это отлично! Вы даже можете создавать интерактивные графики с библиотекой Shiny или Plotly для R. Dash и Shiny похожи, но Dash не стремится быть копией Shiny, так как философии Python и R достаточно различаются, что приводит к необходимости использования разного синтаксиса.

Интерактивное веб-приложение, созданное с помощью Shiny на языке R.

Структурирование данных с MATLAB

Если вы программируете на MATLAB, то вам, возможно, знакома GUIDE — библиотека пользовательского интерфейса для MATLAB. Компания Mathworks была одной из новаторов в области технических вычислений. GUIDE была написана в далёком 2004 году.

Приложение, созданное с помощью библиотеки GUIDE на MATLAB.

Если ваши данные структурированы в базе данных, вы могли бы использовать Tableau или любой другой BI-инструмент. Tableau — восхитительный инструмент. Компания установила новый вектор развития в своей отрасли, согласно которому, у конечного пользователя должна быть автономия, чтобы он мог иметь возможность исследовать данные внутри своей организации. Компания также помогла сделать популярнее концепции детализации данных и перекрёстной фильтрации.

Перекрёстная фильтрация в Tableau.

Dash также служит дополнением к BI-инструментам, наподобие вышеупомянутых. Они отлично подходят для структурирования данных. Но когда дело доходит до преобразования данных и аналитики, превзойти размах и гибкость языков программирования и сообществ, вроде Python, становится труднее. Dash абстрагируется от множества сложностей в создании пользовательских интерфейсов, позволяя вам сделать это красиво для вашей аналитической базы данных.

Виджеты Jupyter

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

Виджеты в Dash похожи на виджеты Jupyter. В Jupyter Notebooks есть возможность добавлять виджеты непосредственно рядом с кодом. В Dash элементы управления хранятся отдельно от вашего кода. Dash больше нацелена на приложения для распространения, чем на распространяемый код и документацию. Вы всегда можете смешивать и сопоставлять инструменты, создавая свои приложения на Dash в среде Jupyter Notebook.

Команде разработчиков Dash также очень нравится проект nteract, который действительно снижает порог вхождения в Python и Jupyter Notebook, позволяя упаковать Jupyter Notebook в виде настольного приложения.

Лицензирование и бизнес-модель с открытым исходным кодом

Стартап поддерживает библиотеки с открытым исходным кодом для Python, R и MATLAB, которые взаимодействуют с plotly.js. Компания также поддерживает веб-приложение для создания диаграмм и подключения их к базам данных (стыковочные библиотеки также распространяются с открытым исходным кодом).

Если вы используете локальную версию с открытым исходным кодом, в таком случае ограничений нет. Вы можете управлять развёртыванием Dash-приложений самостоятельно через платформы вроде Heroku или Digital Ocean.

Если вы ищите вдохновение для создания своих пользовательских интерфейсов в области технических вычислений, рекомендуем прочитать статью Брета Виктора

Вам также может понравиться проект Explorable Explanations, который специализируется на интерактивном обучении.

Перевод статьи «Create Reactive Web Apps in pure Python»

Russian (Pусский) translation by Yuri Yuriev (you can also view the original English article)

В этой серии мы будем использовать Python, Flask и MySQL для создания простого веб-приложения с нуля. Это будет приложение списка дел, в котором пользователи смогут зарегистрироваться, подписаться и создать свой список желаний.

Предполагается, что у вас есть базовые знания языка программирования Python. Мы будем использовать Flask, инфраструктуру веб-приложений Python для создания приложения и MySQL как сервер.

Введение в Python Flask

Flask — это фреймворк Python для создания веб-приложений. С официального сайта,

Flask — это микрофреймворк для Python на основе Werkzeug, Jinja 2 и благих намерений.

Когда мы думаем о Python, первое, что приходит нам в голову, — это Django framework. Но с точки зрения новичка в Python, начинать с Flask легче, чем с Django.

Установка Flask

Установить Flask легко и просто. С менеджером пакетов pip  нужно сделать только:

Когда вы закончите установку Flask, создайте папку   FlaskApp. Перейдите в папку FlaskApp и создайте файл с именем app.py. Импортируйте модуль flask и создайте приложение с помощью Flask, как показано ниже:

1
from flask import Flask
2
app = Flask(__name__)

Теперь определим основной путь / и соответствующий ему обработчик запросов:

1
@app.route("/")
2
def main():
3
    return "Welcome!"

Затем проверьте, является ли исполняемый файл главной программой и запустите приложение:

1
if __name__ == "__main__":
2
    app.run()

Сохраните изменения и выполните app.py:

Укажите браузеру на http://localhost:5000/ и у вас должно появиться приветственное сообщение.

Создание домашней страницы

Во-первых, при запуске приложения мы должны показать домашнюю страницу с последними элементами списка дел, добавленными пользователями. Итак, добавим нашу домашнюю страницу в папку приложения.

Flask ищет файлы шаблонов внутри папки templates. Перейдите в папку PythonApp и создайте папку под названием templates. Внутри templates создайте файл index.html. Откройте index.html и пропишите следующий HTML:

1
<!DOCTYPE html>
2
<html lang="en">
3

4
<head>
5
    <title>Python Flask Bucket List App</title>
6

7

8
    <link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
9

10
    <link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">
11

12

13
</head>
14

15
<body>
16

17
    <div class="container">
18
        <div class="header">
19
            <nav>
20
                <ul class="nav nav-pills pull-right">
21
                    <li role="presentation" class="active"><a href="#">Home</a>
22
                    </li>
23
                    <li role="presentation"><a href="#">Sign In</a>
24
                    </li>
25
                    <li role="presentation"><a href="showSignUp">Sign Up</a>
26
                    </li>
27
                </ul>
28
            </nav>
29
            <h3 class="text-muted">Python Flask App</h3>
30
        </div>
31

32
        <div class="jumbotron">
33
            <h1>Bucket List App</h1>
34
            <p class="lead"></p>
35
            <p><a class="btn btn-lg btn-success" href="showSignUp" role="button">Sign up today</a>
36
            </p>
37
        </div>
38

39
        <div class="row marketing">
40
            <div class="col-lg-6">
41
                <h4>Bucket List</h4>
42
                <p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
43

44
                <h4>Bucket List</h4>
45
                <p>Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet fermentum.</p>
46

47
                <h4>Bucket List</h4>
48
                <p>Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
49
            </div>
50

51
            <div class="col-lg-6">
52
                <h4>Bucket List</h4>
53
                <p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
54

55
                <h4>Bucket List</h4>
56
                <p>Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet fermentum.</p>
57

58
                <h4>Bucket List</h4>
59
                <p>Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
60
            </div>
61
        </div>
62

63
        <footer class="footer">
64
            <p>&copy; Company 2015</p>
65
        </footer>
66

67
    </div>
68
</body>
69

70
</html>

Откройте app.py и импортируйте render_template, который мы будем использовать для рендеринга файлов шаблонов.

1
from flask import Flask, render_template

Измените основной метод, чтобы вернуть созданный файл шаблона.

1
def main():
2
    return render_template('index.html')

Сохраните изменения и перезапустите сервер. Указав браузеру http://localhost:5000/ вы увидите следующее:

Bucket List App home pageBucket List App home pageBucket List App home page

Создание страницы регистрации

Шаг 1. Настройка базы данных

Мы будем использовать MySQL в качестве сервера. Войдите в MySQL из командной строки или, если вы предпочитаете GUI, например, MySQL work bench, тоже можете пользоваться. Сначала создайте базу данных BucketList. Из командной строки:

Введите требуемый пароль и при входе в систему выполните следующую команду для создания базы данных:

1
CREATE DATABASE BucketList;

Как только база данных будет создана, создайте таблицу tbl_user, как показано ниже:

1
CREATE TABLE `BucketList`.`tbl_user` (
2
  `user_id` BIGINT NULL AUTO_INCREMENT,
3
  `user_name` VARCHAR(45) NULL,
4
  `user_username` VARCHAR(45) NULL,
5
  `user_password` VARCHAR(45) NULL,
6
  PRIMARY KEY (`user_id`));

Мы будем использовать Stored procedures в приложении Python для взаимодействия с базой данных MySQL. Поскольку таблица tbl_user была создана, создайте   процедуру сохранения под названием sp_createUser, чтобы зарегистрировать пользователя.

При создании этой процедуры в таблице tbl_user сначала нужно проверить, не существует ли пользователь с тем же именем username. Если существует, нам нужно выдать ошибку, иначе мы создадим пользователя в таблице user. Вот как должна выглядеть процедура sp_createUser :

1
DELIMITER $$
2
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_createUser`(
3
    IN p_name VARCHAR(20),
4
  IN p_username VARCHAR(20),
5
	IN p_password VARCHAR(20)
6
)
7
BEGIN
8
	if ( select exists (select 1 from tbl_user where user_username = p_username) ) THEN
9
	
10
		select 'Username Exists !!';
11
	
12
	ELSE
13
	
14
		insert into tbl_user
15
		(
16
			user_name,
17
			user_username,
18
			user_password
19
		)
20
		values
21
		(
22
			p_name,
23
			p_username,
24
			p_password
25
		);
26
	
27
	END IF;
28
END$$
29
DELIMITER ;

Шаг 2. Создание интерфейса регистрации

Перейдите в каталог PythonApp/templates и создайте файл HTML с именем signup.html. Добавьте следующий код HTML в signup.html:

1
<!DOCTYPE html>
2
<html lang="en">
3
  <head>
4
    <title>Python Flask Bucket List App</title>
5

6
   
7
    <link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
8

9
    <link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">
10
    <link href="../static/signup.css" rel="stylesheet">
11
   
12
  </head>
13

14
  <body>
15

16
    <div class="container">
17
      <div class="header">
18
        <nav>
19
          <ul class="nav nav-pills pull-right">
20
            <li role="presentation" ><a href="main">Home</a></li>
21
            <li role="presentation"><a href="#">Sign In</a></li>
22
            <li role="presentation" class="active"><a href="#">Sign Up</a></li>
23
          </ul>
24
        </nav>
25
        <h3 class="text-muted">Python Flask App</h3>
26
      </div>
27

28
      <div class="jumbotron">
29
        <h1>Bucket List App</h1>
30
        <form class="form-signin">
31
        <label for="inputName" class="sr-only">Name</label>
32
        <input type="name" name="inputName" id="inputName" class="form-control" placeholder="Name" required autofocus>
33
        <label for="inputEmail" class="sr-only">Email address</label>
34
        <input type="email" name="inputEmail" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
35
        <label for="inputPassword" class="sr-only">Password</label>
36
        <input type="password" name="inputPassword" id="inputPassword" class="form-control" placeholder="Password" required>
37
        
38
        <button id="btnSignUp" class="btn btn-lg btn-primary btn-block" type="button">Sign up</button>
39
      </form>
40
      </div>
41

42
      
43

44
      <footer class="footer">
45
        <p>&copy; Company 2015</p>
46
      </footer>
47

48
    </div>
49
  </body>
50
</html>

Добавьте такой CSS как signup.css в постоянную папку внутри PythonApp.

1
body {
2
  padding-top: 40px;
3
  padding-bottom: 40px;
4
}
5

6
.form-signin {
7
  max-width: 330px;
8
  padding: 15px;
9
  margin: 0 auto;
10
}
11
.form-signin .form-signin-heading,
12
.form-signin .checkbox {
13
  margin-bottom: 10px;
14
}
15
.form-signin .checkbox {
16
  font-weight: normal;
17
}
18
.form-signin .form-control {
19
  position: relative;
20
  height: auto;
21
  -webkit-box-sizing: border-box;
22
     -moz-box-sizing: border-box;
23
          box-sizing: border-box;
24
  padding: 10px;
25
  font-size: 16px;
26
}
27
.form-signin .form-control:focus {
28
  z-index: 2;
29
}
30
.form-signin input[type="email"] {
31
  margin-bottom: -1px;
32
  border-bottom-right-radius: 0;
33
  border-bottom-left-radius: 0;
34
}
35
.form-signin input[type="password"] {
36
  margin-bottom: 10px;
37
  border-top-left-radius: 0;
38
  border-top-right-radius: 0;
39
}

В app.py добавьте метод showSignUp для отображения страницы регистрации после поступления запроса в /showSignUp:

1
@app.route('/showSignUp')
2
def showSignUp():
3
    return render_template('signup.html')

Сохраните изменения и перезапустите сервер. Нажмите кнопку Sign Up на главной странице и у вас должна получиться такая страница регистрации:

Sign Up user pageSign Up user pageSign Up user page

Шаг 3. Внедрение метода регистрации

Затем нам нужен server-side метод для UI взаимодействия с базой данных MySQL. Перейдите в PythonApp и откройте app.py. Создайте новый метод signUp, а также добавьте  /signUp. Так это выглядит:

1
@app.route('/signUp')
2
def signUp():
3
    # create user code will be here !!

Мы будем использовать jQuery AJAX для публикации данных регистрации в методе signUp, поэтому укажем метод в определении маршрута.

1
@app.route('/signUp',methods=['POST'])
2
def signUp():
3
    # create user code will be here !!

Чтобы прочитать опубликованные значения, нам нужно импортировать request из Flask.

1
from flask import Flask, render_template, request

С помощью request мы прочитаем значения, как показано ниже:

1
@app.route('/signUp',methods=['POST'])
2
def signUp():
3

4
    # read the posted values from the UI

5
    _name = request.form['inputName']
6
    _email = request.form['inputEmail']
7
    _password = request.form['inputPassword']

Как только значения прочитаны, мы проверяем, верны ли они, а пока давайте вернём простое сообщение:

1
@app.route('/signUp',methods=['POST'])
2
def signUp():
3

4
    # read the posted values from the UI

5
    _name = request.form['inputName']
6
    _email = request.form['inputEmail']
7
    _password = request.form['inputPassword']
8

9
    # validate the received values

10
    if _name and _email and _password:
11
        return json.dumps({'html':'<span>All fields good !!</span>'})
12
    else:
13
        return json.dumps({'html':'<span>Enter the required fields</span>'})

Импортируйте json из Flask, так как мы используем его для возвращения данных json.

1
from flask import Flask, render_template, json, request

Шаг 4. Создание запроса на регистрацию

Мы будем использовать jQuery AJAX для отправки запроса на регистрацию в метод Python. Загрузите jQuery , разместите его внутри PythonApp/static/js и добавьте ссылку на него со страницы регистрации. Как только jQuery будет включен, мы добавим запрос POST JQuery при нажатии кнопки Sign Up.

Итак, давайте присоединим событие нажатия кнопки, как показано:

1
$(function() {
2
    $('#btnSignUp').click(function() {
3

4
        $.ajax({
5
            url: '/signUp',
6
            data: $('form').serialize(),
7
            type: 'POST',
8
            success: function(response) {
9
                console.log(response);
10
            },
11
            error: function(error) {
12
                console.log(error);
13
            }
14
        });
15
    });
16
});

Сохраните изменения и перезапустите сервер. На странице Sign Up заполните данные и нажмите Sign Up. Проверьте браузер, у вас должно получиться следующее сообщение:

1
{"html": "<span>All fields good !!</span>"} 

Шаг 5: вызов хранимой процедуры MySQL

У нас есть nameemail address и password, мы вызываем процедуру MySQL для создания нового пользователя.

Чтобы соединиться с MySQL, мы будем использовать Flask-MySQL, который является расширением Flask. Чтобы начать работу с Flask-MySQL, установите его с помощью менеджера пакетов pip:

1
pip install flask-mysql

Импортируйте MySQL внутрь app.py:

1
from flask.ext.mysql import MySQL

Ранее мы определили наше приложение:

Наряду с этим, включая следующие конфигурации MySQL:

1
mysql = MySQL()
2

3
# MySQL configurations

4
app.config['MYSQL_DATABASE_USER'] = 'jay'
5
app.config['MYSQL_DATABASE_PASSWORD'] = 'jay'
6
app.config['MYSQL_DATABASE_DB'] = 'BucketList'
7
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
8
mysql.init_app(app)

Сначала давайте создадим соединение MySQL:

Когда соединение установлено, нам понадобится cursor для запроса stored процедуры. Через conn соединение создаём курсор.

Перед вызовом stored процедуры, давайте сделаем надёжный пароль с помощником от Werkzeug. Импортируйте модуль в app.py:

1
from werkzeug import generate_password_hash, check_password_hash

Используйте модуль для создания хэшированного пароля.

1
_hashed_password = generate_password_hash(_password)

Теперь вызываем процедуру sp_createUser:

1
cursor.callproc('sp_createUser',(_name,_email,_hashed_password))

Если процедура выполнена успешно, мы зафиксируем изменения и вернем сообщение об успешном завершении.

1
data = cursor.fetchall()
2

3
if len(data) is 0:
4
    conn.commit()
5
    return json.dumps({'message':'User created successfully !'})
6
else:
7
    return json.dumps({'error':str(data[0])})

Сохраните изменения и перезапустите сервер. На странице регистрации введите nameemail address и password и нажмите кнопку Sign Up. После успешного создания пользователя вы увидите сообщение в консоли браузера.

1
{"message": "User created successfully !"}

Подводя итоги

В этом уроке мы рассмотрели начало работы по созданию приложения с помощью Python FlaskMySQL и расширения Flask-MySQL . Мы создали и прописали таблицы базы данных, stored процедуру, а также обеспечили функциональность регистрации. В следующем уроке мы перейдём на уровень выше, реализовав функции входа в систему и некоторые ещё.

Исходный код к этому уроку доступен на GitHub.

Сообщите нам свои мысли в комментариях!

Python

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

Skillfactory.ru

Раньше для демонстрации проекта хватало хороших визуализаций или небольших PPT, однако с появлением таких инструментов для создания дашбордов, как RShiny и Dash, хорошему специалисту по данным стало необходимо разбираться в веб-фреймворках. 

Веб-фреймворки трудно освоить. Я до сих пор путаюсь в HTML, CSS и Javascript, когда нужно создать даже что-то простое. И я уже не говорю о таком большом разнообразии способов выполнить одну и ту же задачу. Просто кошмар для специалистов по работе с данными, для которых веб-разработка — второстепенный навык.

Так что же, мы обречены изучать веб-фреймворки? Или звонить посреди ночи нашим друзьям-разработчикам с глупыми вопросами?

И вот здесь на помощь приходит Streamlit с возможностью создавать веб-приложения на Python. 

Дзен Python: Простое лучше, чем сложное, и Streamlit предельно упрощает создание приложений. 

Эта статья о том, как создавать приложения, поддерживающие проекты по науке о данных, используя Streamlit.

Чтобы лучше понять архитектуру и мыслительный процесс, которые привели к появлению Streamlit, рекомендую почитать пост одного из разработчиков и основателей этого фреймворка.

Установка

Устанавливаем Streamlit — просто запускаем команду: 

pip install streamlit

Проверяем, что установка прошла успешно: 

streamlit hello

Эта команда выведет следующее сообщение на экран: 

Пройдите по локальному URL localhost:8501 в браузере, чтобы увидеть приложение Streamlit в действии. Разработчики предоставили несколько классных демо, с которыми можно поиграть. Прежде чем вернуться к коду, уделите приложению немного времени, чтобы почувствовать пользу инструментов. 

Hello World в Streamlit

Цель Streamlit — упростить разработку приложений с помощью Python.

Давайте напишем простое приложение, чтобы проверить, справится ли Streamlit с задачей.

Начнем с приложения, которое назовем Hello World. Просто поместим код ниже в файл helloworld.py:

import streamlit as st

x = st.slider('x')
st.write(x, 'squared is', x * x)

И запустим файл в терминале: 

streamlit run helloworld.py

Вуаля, вы увидите это приложение в действии в браузере по адресу localhost:8501, оно позволяет вам двигать ползунок и выдает результат. 

Простое приложение с виджетом ползунка

Это было очень просто. В приложении выше мы использовали две фичи Streamlit:

  • виджет st.slider, который можно двигать и менять вывод веб-приложения;
  • универсальную команду st.write. Мне нравится, как она записывает данные из таблиц, наборов данных и простого текста. Подробнее об этом позже. 

Важно: помните, что каждый раз при изменении значения виджета, приложение полностью запускается от начала до конца. 

Виджеты Streamlit 

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

1. Ползунок

streamlit.slider(label, min_value=None, max_value=None, value=None, step=None, format=None)

Выше мы уже видели st.slider в действии. Его можно использовать с min_value, max_value и step для получения выходных данных в диапазоне.

2. Ввод текста

Это самый простой способ получить пользовательский ввод, будь то ввод URL или текста для анализа тональности. Виджету нужен только один лейбл для именования текстового поля:

import streamlit as st

url = st.text_input('Enter URL')
st.write('The Entered URL is', url)

Вот как выглядит приложение: 

Простое приложение с виджетом ввода текста

Подсказка: Можно просто заменить файл helloworld.py и обновить браузер. Я открываю и изменяю helloworld.py в редакторе Sublime text и вижу изменения в браузере рядом.

3. Чекбокс

Один вариант использования чекбокса — скрыть или показать определенную область в приложении. Другой — задать булевое значение в параметрах для функции. st.checkbox() принимает один аргумент — лейбл виджета. 

В этом приложении чекбокс используется для переключения условного оператора:

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")
if st.checkbox('Show dataframe'):
    st.write(df)
Простое приложение с виджетом чекбокса

4. SelectBox

Мы можем использовать st.selectbox для выбора из серии или списка. Обычный вариант использования — простой выпадающий список для выбора значений: 

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")

option = st.selectbox(
    'Which Club do you like best?',
     df['Club'].unique())

'You selected: ', option
Простое приложение с виджетом dropdown/selectbox

5. Множественное выделение

Можно использовать несколько значений из выпадающего списка. Здесь мы используем st.multiselect, чтобы получить несколько значений списком в переменной options:

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")

options = st.multiselect(
 'What are your favorite clubs?', df['Club'].unique())

st.write('You selected:', options)
Простое приложение с виджетом multiselect

Создаем простое приложение 

Теперь мы создадим простое приложение, используя несколько виджетов одновременно. 

Сначала попробуем визуализировать наши футбольные данные: с помощью уже знакомых нам виджетов сделать это не составит труда. 

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")

clubs = st.multiselect('Show Player for clubs?', df['Club'].unique())

nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique())

# Фильтрует данные 
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]

# выводит данные на экран
st.write(new_df)

Наше приложение выглядит так: 

Использование сочетания нескольких виджетов 

Это было просто. Но и выглядит несколько по-простецки. Может, добавить диаграммы? 

В настоящее время Streamlit поддерживает множество библиотек для отображения графических данных. Вот некоторые из них: Plotly, Bokeh, Matplotlib, Altair, and Vega charts. Plotly Express тоже работает, хоть в документации его и нет. Он также содержит встроенные типы диаграмм, нативные для Streamlit, например st.line_chart и st.area_chart.

Мы будем работать с plotly_express. Используем четыре вызова streamlit, все остальное просто код на python:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

df = pd.read_csv("football_data.csv")

clubs = st.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique())
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)

# Создаем график, используя plotly express
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')

# Диаграмма!
st.plotly_chart(fig)
Добавление диаграмм

Улучшения

В самом начале я отметил, что каждый раз при изменении любого виджета приложение полностью запускается от начала до конца. Это не приемлемо, когда мы создаем приложения, обслуживающие модели глубокого обучения или сложные модели машинного обучения. В Streamlit эту проблему решает кэширование

1. Кэширование

В нашем простом приложении мы перечитываем данные снова и снова при изменении значения. Это работает с малым объемом данных и не работает с большими данными или при необходимости много обрабатывать данные. Давайте используем кэширование с помощью функции-декоратора st.cache:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

df = st.cache(pd.read_csv)("football_data.csv")

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

@st.cache
def complex_func(a,b):
    DO SOMETHING COMPLEX

# Не запускается снова и снова. 
complex_func(a,b)

Когда мы помечаем функцию кэш-декоратором, когда бы функция не была вызвана, Streamlit проверяет параметр ввода, с помощью которого вызвана функция. 

Если Streamlit видит эти параметры впервые, он запускает функцию и сохраняет ее в локальный кэш.

Если параметры не изменятся при следующем вызове функции, Streamlit знает, что может вообще пропустить выполнение функции. Он просто использует результат из кэша.

Skillfactory.ru

2. Боковая панель

Для более аккуратного вида в зависимости от ваших предпочтений можно перенести виджеты в боковую панель, что-то вроде дашборда Rshiny. Это очень просто — добавляем st.sidebar в код виджета. 

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

df = st.cache(pd.read_csv)("football_data.csv")

clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique())

new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)

# Создает distplot с пользовательским bin_size
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')

# Диаграмма!
st.plotly_chart(fig)
Перемещение виджета в боковую панель

3. Markdown?

Я люблю писать в Markdown. Как по мне, так он не такой многословный, как HTML, и больше подходит для работы с данными. Итак, можно ли использовать Markdown с приложением Streamlit?

Да, конечно. Существует несколько способов сделать это. Мне лучшим кажется использование магических команд. Они позволяют писать markdown так же просто, как комментарии. Можно использовать команду st.markdown:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

'''
# Приложение Клуб и национальность. 

Это очень простое веб-приложение позволяет выбрать и визуализировать данные игроков нескольких клубов и национальностей. 

'''
df = st.cache(pd.read_csv)("football_data.csv")

clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique())

new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)

# Создаем distplot с пользовательским bin_size
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')

'''
### Здесь простая диаграмма между возрастом игрока и остальными данными
'''st.plotly_chart(fig)
Итоговое демо приложения

Заключение

Streamlit демократизировал полный процесс создания приложений, и невозможно его не порекомендовать. 

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

Мне нравятся цвета и стили по умолчанию, используемые разработчиками. Мне они кажутся намного более комфортными, чем в Dash, который я использовал ранее. В приложениях Streamlit также можно включать аудио и видео. 

Кроме того, Streamlit — это бесплатное приложение с открытым кодом, которое работает прямо из коробки. 

В прошлом мне приходилось обращаться к друзьям-разработчикам за любыми изменениями в демо или презентациях; теперь это стало относительно просто. 

Я не знаю, насколько хорошо streamlit работает в производственной среде, но для демонстрации небольших концептуальных проектов оно идеально.

Весь код рассмотренного приложения можно найти здесь.

Читайте также:

  • 20 фрагментов Python, которые стоит выучить прямо сегодня
  • Введение в модульное тестирование на Python
  • Знакомство с классами в Python

Перевод статьи Rahul Agarwal: How to write Web apps using simple Python for Data Scientists?

Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Deploy Your Python Script on the Web With Flask

You wrote a Python script that you’re proud of, and now you want to show it off to the world. But how? Most people won’t know what to do with your .py file. Converting your script into a Python web application is a great solution to make your code usable for a broad audience.

In this tutorial, you’ll learn how to go from a local Python script to a fully deployed Flask web application that you can share with the world.

By the end of this tutorial, you’ll know:

  • What web applications are and how you can host them online
  • How to convert a Python script into a Flask web application
  • How to improve user experience by adding HTML to your Python code
  • How to deploy your Python web application to Google App Engine

In addition to walking through an example project, you’ll find a number of exercises throughout the tutorial. They’ll give you a chance to solidify what you’re learning through extra practice. You can also download the source code that you’ll use to build your web application by clicking the link below:

Brush Up on the Basics

In this section, you’ll get a theoretical footing in the different topics that you’ll work with during the practical part of this tutorial:

  • What types of Python code distribution exist
  • Why building a web application can be a good choice
  • What a web application is
  • How content gets delivered over the Internet
  • What web hosting means
  • Which hosting providers exist and which one to use

Brushing up on these topics can help you feel more confident when writing Python code for the Web. However, if you’re already familiar with them, then feel free to skip ahead, install the Google Cloud SDK, and start building your Python web app.

Distribute Your Python Code

Bringing your code to your users is called distribution. Traditionally, there are three different approaches you can use to distribute your code so that others can work with your programs:

  1. Python library
  2. Standalone program
  3. Python web application

You’ll take a closer look at each of these approaches below.

Python Library

If you’ve worked with Python’s extensive package ecosystem, then you’ve likely installed Python packages with pip. As a programmer, you might want to publish your Python package on PyPI to allow other users to access and use your code by installing it using pip:

$ python3 -m pip install <your-package-name>

After you’ve successfully published your code to PyPI, this command will install your package, including its dependencies, on any of your users’ computers, provided that they have an Internet connection.

If you don’t want to publish your code as a PyPI package, then you can still use Python’s built-in sdist command to create a source distribution or a Python wheel to create a built distribution to share with your users.

Distributing your code like this keeps it close to the original script you wrote and adds only what’s necessary for others to run it. However, using this approach also means that your users will need to run your code with Python. Many people who want to use your script’s functionality won’t have Python installed or won’t be familiar with the processes required to work directly with your code.

A more user-friendly way to present your code to potential users is to build a standalone program.

Standalone Program

Computer programs come in different shapes and forms, and there are multiple options for transforming your Python scripts into standalone programs. Below you’ll read about two possibilities:

  1. Packaging your code
  2. Building a GUI

Programs such as PyInstaller, py2app, py2exe, or Briefcase can help with packaging your code. They turn Python scripts into executable programs that can be used on different platforms without requiring your users to explicitly run the Python interpreter.

While packaging your code can resolve dependency problems, your code still just runs on the command line. Most people are used to working with programs that provide a graphical user interface (GUI). You can make your Python code accessible to more people by building a GUI for it.

While a standalone GUI desktop program can make your code accessible to a wider audience, it still presents a hurdle for people to get started. Before running your program, potential users have a few steps to get through. They need to find the right version for their operating system, download it, and successfully install it. Some may give up before they make it all the way.

It makes sense that many developers instead build web applications that can be accessed quickly and run on an Internet browser.

Python Web Application

The advantage of web applications is that they’re platform independent and can be run by anyone who has access to the Internet. Their code is implemented on a back-end server, where the program processes incoming requests and responds through a shared protocol that’s understood by all browsers.

Python powers many large web applications and is a common choice as a back-end language. Many Python-driven web applications are planned from the start as web applications and are built using Python web frameworks such as Flask, which you’ll use in this tutorial.

However, instead of the web-first approach described above, you’re going to take a different angle. After all, you weren’t planning to build a web application. You just created a useful Python script, and now you want to share with the world. To make it accessible to a broad range of users, you’ll refactor it into a web application and then deploy it to the Internet.

It’s time to go over what a web application is and how it’s different from other content on the Web.

Learn About Python Web Applications

Historically, websites had fixed content that was the same for every user who accessed that page. These web pages are called static because their content doesn’t change when you interact with them. When serving a static web page, a web server responds to your request by sending back the content of that page, regardless of who you are or what other actions you took.

You can browse an example of a static website at the first URL that ever went online, as well as the pages it links to:

Screenshot of one of the first static webpages, displaying the history of the project as envisioned at CERN

The history of the WWW

Such static websites aren’t considered applications since their content isn’t generated dynamically by code. While static sites used to make up all of the Internet, most websites today are true web applications, which offer dynamic web pages that can change the content they deliver.

For instance, a webmail application allows you to interact with it in many ways. Depending on your actions, it can display different types of information, often while staying in a single page:

A webmail web app page as an example for a dynamic webpage

A single-page Webmail application

Python-driven web applications use Python code to determine what actions to take and what content to show. Your code is run by the web server that hosts your website, which means that your users don’t need to install anything. All they need to interact with your code is a browser and an Internet connection.

Getting Python to run on a website can be complicated, but there are a number of different web frameworks that automatically take care of the details. As mentioned above, you’ll build a basic Flask application in this tutorial.

In the upcoming section, you’ll get a high-level perspective on the main processes that need to happen to run your Python code on a server and deliver a response to your users.

Review the HTTP Request-Response Cycle

Serving dynamic content over the Internet involves a lot of different pieces, and they all have to communicate with one another to function correctly. Here’s a generalized overview of what takes place when a user interacts with a web application:

  1. Sending: First, your user makes a request for a particular web page on your web app. They can do this, for example, by typing a URL into their browser.

  2. Receiving: This request gets received by the web server that hosts your website.

  3. Matching: Your web server now uses a program to match the user’s request to a particular portion of your Python script.

  4. Running: The appropriate Python code is called up by that program. When your code runs, it writes out a web page as a response.

  5. Delivering: The program then delivers this response back to your user through the web server.

  6. Viewing: Finally, the user can view the web server’s response. For example, the resulting web page can be displayed in a browser.

This is a general process of how content is delivered over the Internet. The programming language used on the server, as well as the technologies used to establish that connection, can differ. However, the concept used to communicate across HTTP requests and responses remains the same and is called the HTTP Request-Response Cycle.

To allow Flask to handle requests on the server side, you’ll need to find a place where your Python code can live online. Storing your code online to run a web application is called web hosting, and there are a number of providers offering both paid and free web hosting.

Choose a Hosting Provider: Google App Engine

When choosing a web hosting provider, you need to confirm that it supports running Python code. Many of them cost money, but this tutorial will stick with a free option that’s professional and highly scalable yet still reasonable to set up: Google App Engine.

There are a number of other free options, such as PythonAnywhere, Repl.it, or Heroku that you can explore later on. Using Google App Engine will give you a good start in learning about deploying Python code to the web as it strikes a balance between abstracting away complexity and allowing you to customize the setup.

Google App Engine is part of the Google Cloud Platform (GCP), which is run by Google and represents one of the big cloud providers, along with Microsoft Azure and Amazon Web Services (AWS).

To get started with GCP, download and install the Google Cloud SDK for your operating system. For additional guidance beyond what you’ll find in this tutorial, you can consult Google App Engine’s documentation.

The Google Cloud SDK installation also includes a command-line program called gcloud, which you’ll later use to deploy your web app. Once you’re done with the installation, you can verify that everything worked by typing the following command into your console:

You should receive a text output in your terminal that looks similar to the one below:

app-engine-python 1.9.91
bq 2.0.62
cloud-datastore-emulator 2.1.0
core 2020.11.13
gsutil 4.55

Your version numbers will probably be different, but as long as the gcloud program is successfully found on your computer, your installation was successful.

With this high-level overview of concepts in mind and the Google Cloud SDK installed, you’re ready to set up a Python project that you’ll later deploy to the Internet.

Build a Basic Python Web Application

Google App Engine requires you to use a web framework for creating your web application in a Python 3 environment. Since you’re trying to use a minimal setup to get your local Python code up on the Internet, a microframework such as Flask is a good choice. A minimal implementation of Flask is so small that you might not even notice that you’re using a web framework.

The application you’re going to create will rely on several different files, so the first thing you need to do is to create a project folder to hold all these files.

Set Up Your Project

Create a project folder and give it a name that’s descriptive of your project. For this practice project, call the folder hello-app. You’ll need three files inside this folder:

  1. main.py contains your Python code wrapped in a minimal implementation of the Flask web framework.
  2. requirements.txt lists all the dependencies your code needs to work properly.
  3. app.yaml helps Google App Engine decide which settings to use on its server.

While three files might sound like a lot, you’ll see that this project uses fewer than ten lines of code across all three files. This represents the minimal setup you need to provide to Google App Engine for any Python project you may launch. The rest will be your own Python code. You can download the complete source code that you’ll use in this tutorial by clicking the link below:

Next, you’ll take a look at the content of each of the files starting with the most complex one, main.py.

Create main.py

main.py is the file that Flask uses to deliver your content. At the top of the file, you import the Flask class on line 1, then you create an instance of a Flask app on line 3:

 1from flask import Flask
 2
 3app = Flask(__name__)
 4
 5@app.route("/")
 6def index():
 7    return "Congratulations, it's a web app!"

After you create the Flask app, you write a Python decorator on line 5 called @app.route that Flask uses to connect URL endpoints with code contained in functions. The argument to @app.route defines the URL’s path component, which is the root path ("/") in this case.

The code on lines 6 and 7 makes up index(), which is wrapped by the decorator. This function defines what should be executed if the defined URL endpoint is requested by a user. Its return value determines what a user will see when they load the page.

In other words, if a user types the base URL of your web app into their browser, then Flask runs index() and the user sees the returned text. In this case, that text is just one sentence: Congratulations, it's a web app!

You can render more complex content, and you can also create more than one function so that users can visit different URL endpoints in your app to receive different responses. However, for this initial implementation, it’s fine to stick with this short and encouraging success message.

Create requirements.txt

The next file to look at is requirements.txt. Since Flask is the only dependency of this project, that’s all you need to specify:

If your app has other dependencies, then you’ll need to add them to your requirements.txt file as well.

Google App Engine will use requirements.txt to install the necessary Python dependencies for your project when setting it up on the server. This is similar to what you would do after creating and activating a new virtual environment locally.

Create app.yaml

The third file, app.yaml, helps Google App Engine set up the right server environment for your code. This file requires only one line, which defines the Python runtime:

The line shown above clarifies that the right runtime for your Python code is Python 3.8. This is enough for Google App Engine to do the necessary setup on its servers.

You can use Google App Engine’s app.yaml file for additional setup, such as adding environment variables to your application. You can also use it to define the path to static content for your app, such as images, CSS or JavaScript files. This tutorial won’t go into these additional settings, but you can consult Google App Engine’s documentation on the app.yaml Configuration File if you want to add such functionality.

These nine lines of code complete the necessary setup for this app. Your project is now ready for deployment.

However, it’s good practice to test your code before putting it into production so you can catch potential errors. Next, you’ll check whether everything works as expected locally before deploying your code to the Internet.

Test Locally

Flask comes packaged with a development web server. You can use this development server to double-check that your code works as expected. To be able to run the Flask development server locally, you need to complete two steps. Google App Engine will do the same steps on its servers once you deploy your code:

  1. Set up a virtual environment.
  2. Install the flask package.

To set up a Python 3 virtual environment, navigate to your project folder on your terminal and type the following command:

This will create a new virtual environment named venv using the version of Python 3 that you have installed on your system. Next, you need to activate the virtual environment by sourcing the activation script:

$ source venv/bin/activate

After executing this command, your prompt will change to indicate that you’re now operating from within the virtual environment. After you successfully set up and activate your virtual environment, you’re ready to install Flask:

$ python3 -m pip install -r requirements.txt

This command fetches all packages listed in requirements.txt from PyPI and installs them in your virtual environment. In this case, the only package installed will be Flask.

Wait for the installation to complete, then open up main.py and add the following two lines of code at the bottom of the file:

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8080, debug=True)

These two lines tell Python to start Flask’s development server when the script is executed from the command line. It’ll be used only when you run the script locally. When you deploy the code to Google App Engine, a professional web server process, such as Gunicorn, will serve the app instead. You won’t need to change anything to make this happen.

You can now start Flask’s development server and interact with your Python app in your browser. To do so, you need to run the Python script that starts the Flask app by typing the following command:

Flask starts up the development server, and your terminal will display output similar to the text shown below:

 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: This is a development server.
   Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 315-059-987

This output tells you three important pieces of information:

  1. WARNING: This is Flask’s development server, which means you don’t want to use it to serve your code in production. Google App Engine will handle that for you instead.

  2. Running on http://127.0.0.1:8080/: This is the URL where you can find your app. It’s the URL for your localhost, which means the app is running on your own computer. Navigate to that URL in your browser to see your code live.

  3. Press CTRL+C to quit: The same line also tells you that you can exit the development server by pressing Ctrl+C on your keyboard.

Follow the instructions and open a browser tab at http://127.0.0.1:8080/. You should see a page displaying the text that your function returns: Congratulations, it's a web app!

You can use Flask’s development server to inspect any changes that you make to the code of your Python app. The server listens to changes you make in the code and will automatically reload to display them. If your app doesn’t render as you expect it to on the development server, then it won’t work in production either. So make sure that it looks good before you deploy it.

Also keep in mind that even if it works well locally, it might not work quite the same once deployed. This is because there are other factors involved when you deploy your code to Google App Engine. However, for a basic app such as the one you’re building in this tutorial, you can be confident that it’ll work in production if it works well locally.

Change the return value of index() and confirm that you can see the change reflected in your browser. Play around with it. What happens when you change the return value of index() to HTML code, such as <h1>Hello</h1>, instead of using a plain text string?

After having checked your setup and the code’s functionality on your local development server, you’re prepared to deploy it to Google App Engine.

Deploy Your Python Web Application

It’s finally time to bring your app online. But first, your code needs a place to live on Google’s servers, and you need to make sure that it gets there safely. In this section of the tutorial, you’ll work on completing the necessary deployment setups both in the cloud and locally.

Set Up on Google App Engine

Read through the setup process below step by step. You can compare what you see in your browser with the screenshots. The project name used in the example screenshots is hello-app.

Start by signing in to the Google Cloud Platform. Navigate to the dashboard view, where you’ll see a toolbar at the top of the window. Select the downward-facing arrow button toward the left side of the toolbar. This will pop up a modal containing a list of your Google projects:

Dropdown for viewing all of your Google projects

The modal displays a list of your projects. The list may be empty if you haven’t created any projects yet. On the top right of that modal, find the NEW PROJECT button and click it:

Button to create a new project on Google App Engine

Clicking NEW PROJECT will redirect you to a new page where you can decide on a name for your project. This name will appear in the URL of your application, which will look similar to http://your-application-name.nw.r.appspot.com. Use hello-app as the name for this project to stay consistent with the tutorial:

Input field for assigning a project name to a GAE project

You can see your project ID below the Project name input field. The project ID consists of the name you entered and a number that Google App Engine adds. In the case of this tutorial, you can see that the project ID is hello-app-295110. Copy your personal project ID since you’ll need it later on for deploying.

You can now click CREATE and wait for the project to be set up on Google App Engine’s side. Once that’s done, a notification will pop up telling you that a new project has been created. It also gives you the option to select it. Go ahead and do that by clicking SELECT PROJECT:

Screenshot showing the option to Select Project

Clicking SELECT PROJECT will redirect you to the main page of your new Google Cloud Platform project. It looks like this:

Google Cloud Platform dashboard view

From here, you want to switch to the dashboard of Google App Engine. You can do that by clicking the hamburger menu on the top left, scrolling down to select App Engine in the first list, then selecting Dashboard on the top of the next pop-up list:

Visual instructions on how to get from the Cloud Platform dashboard to the App Engine dashboard

This will finally redirect you to the Google App Engine dashboard view of your new project. Since the project is empty so far, the page will look similar to this:

New project page on GAE after successfully creating a new project

When you see this page, it means you have completed setting up a new project on Google App Engine. You’re now ready to head back to the terminal on your computer and complete the local steps necessary to deploy your app to this project.

Set Up Locally for Deployment

After successfully installing the Google Cloud SDK, you have access to the gcloud command-line interface. This program comes with helpful instructions that guide you through deploying your web app. Start by typing the command that was suggested to you when you created a new project on the Google App Engine website:

New project page with gcloud CLI command suggested highlighted

As you can see in the bottom-right corner of the page, Google App Engine suggests a terminal command to deploy your code to this project. Open up your terminal, navigate to your project folder, then run the suggested command:

When you execute this command without any previous setup, the program will respond with an error message:

ERROR: (gcloud.app.deploy)
You do not currently have an active account selected.
Please run:

  $ gcloud auth login

to obtain new credentials.

If you have already logged in with a different account:

    $ gcloud config set account ACCOUNT

to select an already authenticated account to use.

You receive this error message because you can’t deploy any code to your Google App Engine account unless you prove to Google that you’re the owner of that account. You’ll need to authenticate with your Google App Engine account from your local computer.

The gcloud command-line app already provided you with the command that you need to run. Type it into your terminal:

This will start the authentication process by generating a validation URL and opening it up in your browser. Complete the process by selecting your Google account in the browser window and granting Google Cloud SDK the necessary privileges. After you do this, you can return to your terminal, where you’ll see some information about the authentication process:

Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?client_id=<yourid>

You are now logged in as [<your@email.com>].
Your current project is [None].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID

If you see this message, then the authentication was successful. You can also see that the command-line program again offers you helpful information about your next step.

It tells you that there is currently no project set, and that you can set one by running gcloud config set project PROJECT_ID. Now you’ll need the project ID that you noted earlier.

Be sure to replace hello-app-295110 with your own project ID when running the suggested command:

$ gcloud config set project hello-app-295110

Your terminal will print out a short feedback message that the project property has been updated. After successfully authenticating and setting the default project to your project ID, you have completed the necessary setup steps.

Run the Deployment Process

Now you’re ready to try the initial deployment command a second time:

The gcloud app fetches your authentication credentials as well as the project ID information from the default configuration that you just set up and allows you to proceed. Next, you need to select a region where your application should be hosted:

You are creating an app for project [hello-app-295110].
WARNING: Creating an App Engine application for a project is
irreversible and the region cannot be changed.
More information about regions is at
<https://cloud.google.com/appengine/docs/locations>.

Please choose the region where you want your App Engine application
located:

 [1] asia-east2
 [2] asia-northeast1
 [3] asia-northeast2
 [4] asia-northeast3
 [5] asia-south1
 [6] asia-southeast2
 [7] australia-southeast1
 [8] europe-west
 [9] europe-west2
 [10] europe-west3
 [11] europe-west6
 [12] northamerica-northeast1
 [13] southamerica-east1
 [14] us-central
 [15] us-east1
 [16] us-east4
 [17] us-west2
 [18] us-west3
 [19] us-west4
 [20] cancel
Please enter your numeric choice:

Enter one of the numbers that are listed on the left side and press Enter.

After you enter a number, the CLI will continue with the setup process. Before deploying your code to Google App Engine, it’ll show you an overview of what the deployment will look like and ask you for a final confirmation:

Creating App Engine application in project [hello-app-295110]
and region [europe-west]....done.
Services to deploy:

descriptor:      [/Users/realpython/Documents/helloapp/app.yaml]
source:          [/Users/realpython/Documents/helloapp]
target project:  [hello-app-295110]
target service:  [default]
target version:  [20201109t112408]
target url:      [https://hello-app-295110.ew.r.appspot.com]


Do you want to continue (Y/n)?

After you confirm the setup by typing Y, your deployment will finally be on its way. Your terminal will show you some more information and a small loading animation while Google App Engine sets up your project on its servers:

Beginning deployment of service [default]...
Created .gcloudignore file. See `gcloud topic gcloudignore` for details.
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 3 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...⠼

Since this is the first deployment of your web app, it may take a few minutes to complete. Once the deployment is finished, you’ll see another helpful output in the console. It’ll look similar to the one below:

Deployed service [default] to [https://hello-app-295110.ew.r.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse

You can now navigate to the mentioned URL in your browser, or type the suggested command gcloud app browse to access your live web app. You should see the same short text response that you saw earlier when running the app on your localhost: Congratulations, it's a web app!

Notice that this website has a URL that you can share with other people, and they’ll be able to access it. You now have a live Python web application!

Change the return value of index() again and deploy your app a second time using the gcloud app deploy command. Confirm that you can see the change reflected on the live website in your browser.

With this, you’ve completed the necessary steps to get your local Python code up on the web. However, the only functionality that you’ve put online so far is printing out a string of text.

Time to step it up! Following the same process, you’ll bring more interesting functionality online in the next section. You’ll refactor the code of a local temperature converter script into a Flask web app.

Convert a Script Into a Web Application

Since this tutorial is about creating and deploying Python web applications from code you already have, the Python code for the temperature converter script is provided for you here:

def fahrenheit_from(celsius):
    """Convert Celsius to Fahrenheit degrees."""
    try:
        fahrenheit = float(celsius) * 9 / 5 + 32
        fahrenheit = round(fahrenheit, 3)  # Round to three decimal places
        return str(fahrenheit)
    except ValueError:
        return "invalid input"

if __name__ == "__main__":
    celsius = input("Celsius: ")
    print("Fahrenheit:", fahrenheit_from(celsius))

This is a short script that allows a user to convert a Celsius temperature to the equivalent Fahrenheit temperature.

Save the code as a Python script and give it a spin. Make sure that it works as expected and that you understand what it does. Feel free to improve the code.

With this working script in hand, you’ll now need to change the code to integrate it into your Flask app. There are two main points to consider for doing that:

  • Execution: How will the web app know when to run the code?
  • User input: How will the web app collect user input?

You already learned how to tell Flask to execute a specific piece of code by adding the code to a function that you assign a route to. Start by tackling this task first.

Add Code as a Function

Flask separates different tasks into different functions that are each assigned a route through the @app.route decorator. When the user visits the specified route via its URL, the code inside the corresponding function gets executed.

Start by adding fahrenheit_from() to your main.py file and wrapping it with the @app.route decorator:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Congratulations, it's a web app!"

@app.route("/")
def fahrenheit_from(celsius):
    """Convert Celsius to Fahrenheit degrees."""
    try:
        fahrenheit = float(celsius) * 9 / 5 + 32
        fahrenheit = round(fahrenheit, 3)  # Round to three decimal places
        return str(fahrenheit)
    except ValueError:
        return "invalid input"

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8080, debug=True)

So far, you’ve only copied the code of your Python script into a function in your Flask app and added the @app.route decorator.

However, there’s already a problem with this setup. What happens when you run the code in your development server? Give it a try.

Currently, both of your functions are triggered by the same route ("/"). When a user visits that route, Flask picks the first function that matches it and executes that code. In your case, this means that fahrenheit_from() never gets executed because index() matches the same route and gets called first.

Your second function will need its own unique route to be accessible. Additionally, you still need to allow your users to provide input to your function.

Pass Values to Your Code

You can solve both of these tasks by telling Flask to treat any remaining part of the URL following the base URL as a value and pass it on to your function. This requires only a small change to the parameter of the @app.route decorator before fahrenheit_from():

@app.route("/<celsius>")
def fahrenheit_from(celsius):
    # -- snip --

The angle bracket syntax (<>) tells Flask to capture any text following the base URL ("/") and pass it on to the function the decorator wraps as the variable celsius. Note that fahrenheit_from() requires celsius as an input.

Head back to your web browser and try out the new functionality using Flask’s development server. You’re now able to access both of your functions through your web app using different URL endpoints:

  • Index (/): If you go to the base URL, then you’ll see the short encouraging message from before.
  • Celsius (/42): If you add a number after the forward slash, then you’ll see the converted temperature appear in your browser.

Play around with it some more and try entering different inputs. Even the error handling from your script is still functional and displays a message when a user enters a nonnumeric input. Your web app handles the same functionality as your Python script did locally, only now you can deploy it to the Internet.

Refactor Your Code

Flask is a mature web framework that allows you to hand over a lot of tasks to its internals. For example, you can let Flask take care of type checking the input to your function and returning an error message if it doesn’t fit. All this can be done with a concise syntax inside of the parameter to @app.route. Add the following to your path capturer:

@app.route("/<int:celsius>")

Adding int: before the variable name tells Flask to check whether the input it receives from the URL can be converted to an integer. If it can, then the content is passed on to fahrenheit_from(). If it can’t, then Flask displays a Not Found error page.

After applying Flask’s type check, you can now safely remove the tryexcept block in fahrenheit_from(). Only integers will ever be passed on to the function by Flask:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Congratulations, it's a web app!"

@app.route("/<int:celsius>")
def fahrenheit_from(celsius):
    """Convert Celsius to Fahrenheit degrees."""
    fahrenheit = float(celsius) * 9 / 5 + 32
    fahrenheit = round(fahrenheit, 3)  # Round to three decimal places
    return str(fahrenheit)

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8080, debug=True)

With this, you’ve completed converting your temperature conversion script into a web app. Confirm that everything works as expected locally, then deploy your app again to Google App Engine.

Refactor index(). It should return text that explains how to use the temperature converter web app. Keep in mind that you can use HTML tags in the return string. The HTML will render properly on your landing page.

After successfully deploying your temperature conversion web app to the Internet, you now have a link that you can share with other people and allow them to convert Celsius temperatures to Fahrenheit temperatures.

However, the interface still looks quite basic and the web app functions more like an API than a front-end web app. Many users might not know how to interact with your Python web application in its current state. This shows you the limitations of using pure Python for web development.

If you want to create more intuitive interfaces, then you’ll need to start using at least a little bit of HTML.

In the next section, you’ll keep iterating over your code and use HTML to create an input box that allows users to enter a number directly on the page rather than through the URL.

Improve the User Interface of Your Web Application

In this section, you’ll learn how to add an HTML <form> input element to your web app to allow users to interact with it in a straightforward manner that they’re used to from other online applications.

To improve the user interface and user experience of your web app, you’ll need to work with languages other than Python, namely front-end languages such as HTML, CSS, and JavaScript. This tutorial avoids going into these as much as possible, to remain focused on using Python.

However, if you want to add an input box to your web app, then you’ll need to use some HTML. You’ll implement only the absolute minimum to get your web app looking and feeling more like a website that users will be familiar with. You’ll use the HTML <form> element to collect their input.

After the update to your web app, you’ll have a text field where the user can input a temperature in degrees Celsius. There will be a Convert button to convert the user-supplied Celsius temperature into degrees Fahrenheit:

The converted result will be displayed on the next line and will be updated whenever the user clicks Convert.

You’ll also change the functionality of the app so that both the form and the conversion result are displayed on the same page. You’ll refactor the code so that you only need a single URL endpoint.

Collect User Input

Start by creating a <form> element on your landing page. Copy the following few lines of HTML into the return statement of index(), replacing the text message from before:

@app.route("/")
def index():
    return """<form action="" method="get">
                <input type="text" name="celsius">
                <input type="submit" value="Convert">
              </form>"""

When you reload your page at the base URL, you’ll see an input box and a button. The HTML renders correctly. Congratulations, you just created an input form!

What happens when you enter a value and then click Convert? While the page looks just the same, you might notice that the URL changed. It now displays a query parameter with a value after the base URL.

For example, if you entered 42 into the text box and clicked the button, then your URL would look like this: http://127.0.0.1:8080/?celsius=42. This is good news! The value was successfully recorded and added as a query parameter to the HTTP GET request. Seeing this URL means that you’re once again requesting the base URL, but this time with some extra values that you’re sending along.

However, nothing currently happens with that extra value. While the form is set up as it should be, it’s not yet correctly connected to the code functionality of your Python web app.

In order to understand how to make that connection, you’ll read about each piece of the <form> element to see what the different parts are all about. You’ll look at the following three elements and their attributes separately:

  1. <form> element
  2. Input box
  3. Submit button

Each of these are separate HTML elements. While this tutorial aims to keep the focus on Python rather than HTML, it’ll still be helpful to have a basic understanding of what goes on in this block of HTML code. Start by looking at the outermost HTML element.

<form> Element

The <form> element creates an HTML form. The other two <input> elements are wrapped inside it:

<form action="" method="get">
  <input type="text" name="celsius" />
  <input type="submit" value="Convert" />
</form>

The <form> element also contains two HTML attributes called action and method:

  • action determines where the data that the user submits will be sent. You’re leaving the value as an empty string here, which makes your browser direct the request to the same URL it was called from. In your case, that’s the empty base URL.

  • method defines what type of HTTP request the form produces. Using the default of "get" creates an HTTP GET request. This means that the user-submitted data will be visible in the URL query parameters. If you were submitting sensitive data or communicating with a database, then you would need to use an HTTP POST request instead.

After inspecting the <form> element and its attributes, your next step is to take a closer look at the first of the two <input> elements.

Input Box

The second HTML element is an <input> element that’s nested inside the <form> element:

<form action="" method="get">
  <input type="text" name="celsius" />
  <input type="submit" value="Convert" />
</form>

The first <input> element has two HTML attributes:

  1. type defines what type of <input> element should be created. There are many to choose from, such as checkboxes and drop-down elements. In this case, you want the user to enter a number as text, so you’re setting the type to "text".

  2. name defines what the value the user enters will be referred to as. You can think of it as the key to a dictionary, where the value is whatever the user inputs into the text box. You saw this name show up in the URL as the key of the query parameter. You’ll need this key later to retrieve the user-submitted value.

HTML <input> elements can have different shapes, and some of them require different attributes. You’ll see an example of this when looking at the second <input> element, which creates a Submit button and is the last HTML element that makes up your code snippet.

Submit Button

The second <input> element creates the button that allows your users to submit their input:

<form action="" method="get">
  <input type="text" name="celsius" />
  <input type="submit" value="Convert" />
</form>

This element also has two HTML attributes, which are named type and value:

  • type defines what sort of input element will be created. Using the value "submit" creates a button that allows you to send the bundled-up form data onwards.

  • value defines what text the button should display. Feel free to change it to see how the button displays your changed text.

With this short overview of the different HTML elements and their attributes in mind, you now have a better understanding of what you’re adding to your Python code and what the elements are used for.

The information that you’ll need to connect your form submission to your Flask code is the first <input> element’s name value, celsius, which you’ll use to access the submitted value in your function.

Next, you’ll learn how to change your Python code to correctly process the submitted form input.

Receive User Input

In the action attribute of your <form> element, you specified that the data of your HTML form should be sent back to the same URL it came from. Now you need to include the functionality to fetch the value in index(). For this, you need to accomplish two steps:

  1. Import Flask’s request object: Like many web frameworks, Flask passes HTTP requests along as global objects. In order to be able to use this global request object, you first need to import it.

  2. Fetch the value: The request object contains the submitted value and gives you access to it through a Python dictionary syntax. You need to fetch it from the global object to be able to use it in your function.

Rewrite your code and add these two changes now. You’ll also want to add the captured value at the end of the form string to display it after the form:

from flask import Flask
from flask import request

app = Flask(__name__)

@app.route("/")
def index():
    celsius = request.args.get("celsius", "")
    return (
        """<form action="" method="get">
                <input type="text" name="celsius">
                <input type="submit" value="Convert">
            </form>"""
        + celsius
    )

@app.route("/<int:celsius>")
def fahrenheit_from(celsius):
    """Convert Celsius to Fahrenheit degrees."""
    fahrenheit = float(celsius) * 9 / 5 + 32
    fahrenheit = round(fahrenheit, 3)  # Round to three decimal places
    return str(fahrenheit)

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8080, debug=True)

The request.args dictionary contains any data submitted with an HTTP GET request. If your base URL gets called initially, without a form submission, then the dictionary will be empty and you’ll return an empty string as the default value instead. If the page gets called through submitting the form, then the dictionary will contain a value under the celsius key, and you can successfully fetch it and add it to the returned string.

Give it a spin! You’re now able to enter a number and see it displayed right underneath the form’s button. If you enter a new number, then the old one gets replaced. You’re correctly sending and receiving the data that your users are submitting.

Before you move on to integrate the submitted value with your temperature converter code, are there any potential problems you can think of with this implementation?

What happens when you enter a string instead of a number? Give it a try.

Now enter the short HTML code <marquee>BUY USELESS THINGS!!!</marquee> and press Convert.

Currently, your web app accepts any kind of input, be it a number, a string, or even HTML or JavaScript code. This is extremely dangerous because your users might accidentally or intentionally break your web app by entering specific types of content.

Most of the time you should allow Flask to take care of these security issues automatically by using a different project setup. However, you’re in this situation now, so it’s good idea to find out how you can manually make the form you created input safe.

Escape User Input

Taking input from a user and displaying that input back without first investigating what you’re about to display is a huge security hole. Even without malicious intent, your users might do unexpected things that cause your application to break.

Try to hack your unescaped input form by adding some HTML text to it. Instead of entering a number, copy the following line of HTML code, paste it into your input box, and click Convert:

<marquee><a href="https://www.realpython.com">CLICK ME</a></marquee>

Flask inserts the text directly into HTML code, which causes this text input to get interpreted as HTML tags. Because of that, your browser renders the code dutifully, as it would with any other HTML. Instead of displaying back the input as text, you suddenly have to deal with a stylish educational spam link that time-traveled here right from the ’90s:

While this example is harmless and goes away with a refresh of your page, you can imagine how this might present a security problem when other types of content are added in this way. You don’t want to open up the possibility of your users editing aspects of your web app that aren’t meant to be edited.

To avoid this, you can use Flask’s built-in escape(), which converts the special HTML characters <, >, and & into equivalent representations that can be displayed correctly.

You’ll first need to import escape into your Python script to use this functionality. Then, when you submit the form, you can convert any special HTML characters and make your form input ’90s hacker–proof:

from flask import Flask
from flask import request, escape

app = Flask(__name__)

@app.route("/")
def index():
    celsius = str(escape(request.args.get("celsius", "")))
    return (
        """<form action="" method="get">
                <input type="text" name="celsius">
                <input type="submit" value="Convert">
            </form>"""
        + celsius
    )

@app.route("/<int:celsius>")
def fahrenheit_from(celsius):
    """Convert Celsius to Fahrenheit degrees."""
    fahrenheit = float(celsius) * 9 / 5 + 32
    fahrenheit = round(fahrenheit, 3)  # Round to three decimal places
    return str(fahrenheit)

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8080, debug=True)

Refresh your development server and try submitting some HTML code. Now it’ll be displayed back to you as the text string that you entered.

After learning how to collect user input and also how to escape it, you’re finally ready to implement the temperature conversion functionality and show a user the Fahrenheit equivalent of the Celsius temperature they entered.

Process User Input

Since this approach uses only one URL endpoint, you can’t rely on Flask to type check the user input via URL path component capturing as you did earlier on. This means you’ll want to reintroduce your tryexcept block from the initial fahrenheit_from() of the original code.

This time, fahrenheit_from() won’t be associated with an @app.route decorator. Go ahead and delete that line of code. You’ll call fahrenheit_from() explicitly from index() instead of asking Flask to execute it when a specific URL endpoint is accessed.

After deleting the decorator from fahrenheit_from() and reintroducing the tryexcept block, you’ll next add a conditional statement to index() that checks whether the global request object contains a celsius key. If it does, then you want to call fahrenheit_from() to calculate the corresponding Fahrenheit degrees. If it doesn’t, then you assign an empty string to the fahrenheit variable instead.

Doing this allows you to add the value of fahrenheit to the end of your HTML string. The empty string won’t be visible on your page, but if the user submitted a value, then it’ll show up underneath the form.

After applying these final changes, you complete the code for your temperature converter Flask app:

 1from flask import Flask
 2from flask import request
 3
 4app = Flask(__name__)
 5
 6@app.route("/")
 7def index():
 8    celsius = request.args.get("celsius", "")
 9    if celsius:
10        fahrenheit = fahrenheit_from(celsius)
11    else:
12        fahrenheit = ""
13    return (
14        """<form action="" method="get">
15                Celsius temperature: <input type="text" name="celsius">
16                <input type="submit" value="Convert to Fahrenheit">
17            </form>"""
18        + "Fahrenheit: "
19        + fahrenheit
20    )
21
22def fahrenheit_from(celsius):
23    """Convert Celsius to Fahrenheit degrees."""
24    try:
25        fahrenheit = float(celsius) * 9 / 5 + 32
26        fahrenheit = round(fahrenheit, 3)  # Round to three decimal places
27        return str(fahrenheit)
28    except ValueError:
29        return "invalid input"
30
31if __name__ == "__main__":
32    app.run(host="127.0.0.1", port=8080, debug=True)

Since there have been quite a few changes, here’s a step-by-step review of the edited lines:

  • Line 2: You’re not using flask.escape() anymore, so you can remove it from the import statement.

  • Lines 8, 11, and 12: As before, you’re fetching the user-submitted value through Flask’s global request object. By using the dictionary method .get(), you assure that an empty string gets returned if the key isn’t found. That’ll be the case if the page is loaded initially and the user hasn’t submitted the form yet. This is implemented in lines 11 and 12.

  • Line 19: By returning the form with the default empty string stuck to the end, you avoid displaying anything before the form has been submitted.

  • Lines 9 and 10: After your users enter a value and click Convert, the same page gets loaded again. This time around, request.args.get("celsius", "") finds the celsius key and returns the associated value. This makes the conditional statement evaluate to True, and the user-provided value is passed to fahrenheit_from().

  • Lines 24 to 29: fahrenheit_from() checks if the user supplied a valid input. If the provided value can be converted to a float, then the function applies the temperature conversion code and returns the temperature in Fahrenheit. If it can’t be converted, then a ValueError exception is raised, and the function returns the string "invalid input" instead.

  • Line 19: This time, when you concatenate the fahrenheit variable to the end of the HTML string, it points to the return value of fahrenheit_from(). This means that either the converted temperature or the error message string will be added to your HTML.

  • Lines 15 and 18: To make the page easier to use, you also add the descriptive labels Celsius temperature and Fahrenheit to this same HTML string.

Your page will render correctly even though the way you’re adding these strings doesn’t represent valid HTML. This works thanks to the power of modern browsers.

Keep in mind that if you’re interested in diving deeper into web development, then you’ll need to learn HTML. But for the sake of getting your Python script deployed online, this will do just fine.

You should now be able to use your temperature conversion script inside your browser. You can supply a Celsius temperature through the input box, click the button, and see the converted Fahrenheit result appear on the same web page. Since you’re using the default HTTP GET request, you can also see the submitted data appear in the URL.

Deploy your finished application again to Google App Engine using the gcloud app deploy command. Once the deployment is done, go to the provided URL or run gcloud app browse to see your Python web application live on the Internet. Test it out by adding different types of input. Once you’re satisfied, share your link with the world.

The URL of your temperature converter web application still looks something like https://hello-app-295110.ew.r.appspot.com/. This doesn’t reflect the current functionality of your app.

Revisit the deployment instructions, create a new project on Google App Engine with a better fitting name, and deploy your app there. This will give you practice in creating projects and deploying your Flask apps to Google App Engine.

At this point, you’ve successfully converted your Python script into a Python web app and deployed it to Google App Engine for online hosting. You can use the same process to convert more of your Python scripts into web apps.

Create your own poem generator that allows users to create short poems using a web form. Your web application should use a single page with a single form that accepts GET requests. You can use this example code to get started, or you can write your own.

If you want to learn more about what you can do with Google App Engine, then you can read about using static files and add a CSS file to your Python web application to improve its overall appearance.

Hosting your code online can make it accessible to more people over the Internet. Go ahead and convert your favorite scripts into Flask applications and show them to the world.

Conclusion

You covered a lot of ground in this tutorial! You started with a local Python script and transformed it into a user-friendly, fully deployed Flask application that’s now hosted on Google App Engine.

While working through this tutorial, you learned:

  • How web applications provide data over the Internet
  • How to refactor your Python script so you can host it online
  • How to create a basic Flask application
  • How to manually escape user input
  • How to deploy your code to Google App Engine

You can now take your local Python scripts and make them available online for the whole world to use. If you’d like to download the complete code for the application you built in this tutorial, then you can click the link below:

If you want to learn more about web development with Python, then you’re now well equipped to experiment with Python web frameworks such as Flask and Django. Keep up the good work!

Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Deploy Your Python Script on the Web With Flask

Содержание

  1. Установка
  2. Виджеты Streamlit
  3. 1. Слайдер
  4. 2. Ввод текста
  5. 3. Чекбокс
  6. 4. Выпадающий список
  7. 5. Выбор нескольких значений
  8. Пошаговое создание простого приложения
  9. Возможные улучшения
  10. 1. Кэширование
  11. 2. Сайдбар
  12. 3. Markdown
  13. Заключение

Проект по машинному обучению никогда не будет по-настоящему завершен, пока мы не сможем продемонстрировать его результаты. В прошлом хорошо сделанной визуализации или небольшой презентации в Power Point было достаточно для демонстрации проекта, но сейчас, с появлением инструментов для создания дашбордов вроде RShiny или Dash, хороший data science-специалист должен иметь некоторое представление о веб-фреймворках.

Но проблема в том, что веб-фреймворки достаточно сложны в изучении. Я до сих пор путаюсь по всех этих HTML, CSS и Javascript, и даже что-то, что выглядит простым в исполнении, начинает работать только после большого количества проб и ошибок. Не говоря уж о том, что существует огромное количество способов сделать одно и то же, и это сбивает с толку людей, для которых веб-разработка является второстепенным навыком.

Так что же, мы обречены на изучение веб-фреймворков? Или на звонки нашим друзьям-разработчикам посреди ночи с глупыми вопросами?

И тут нам на выручку спешит Streamlit с обещанием позволить нам создавать веб-приложения, используя только Python. Следуя философии Python – “просто – лучше, чем сложно”, Streamlit предельно упрощает создание приложений.

В этой статье я хочу показать как создавать приложения для демонстрации data science-проектов с помощью Streamlit. Чтобы лучше понять архитектуру Streamlit, а также идеи, которые привели к его созданию, прочитайте отличную статью одного из разработчиков и основателей Адриана Трёля.

Курс

Полный курс по Data Science

Освойте самую востребованную профессию 2021 года за 12 месяцев. Дополнительная скидка 5% по промокоду BLOG.

Узнать больше

Установка

Установить Streamlit очень просто, делается это с помощью одной команды: 

pip install streamlit

Чтобы проверить успешно ли прошла установка, можно использовать

streamlit hello

После этой команды на экране должен появиться следующий текст:

Теперь вы можете перейти по локальному URL localhost:8501 в вашем браузере, чтобы увидеть Streamlit в действии. Разработчики предоставили несколько демо, которые будет интересно изучить. Не торопитесь и постарайтесь понять широкие возможности приложения, прежде чем вернуться к этой статье.


Streamlit Hello World

Streamlit стремится сделать разработку приложений проще с использованием исключительно Python.

Давайте попробуем написать простое приложение, чтобы увидеть получилось ли это у них.

Я начну с простого приложения, которое мы назовем Streamlit Hello World. Просто скопируйте текст ниже в файл с названием helloworld.py:

import streamlit as st
x = st.slider('x')
st.write(x, 'squared is', x * x)

И используйте в терминале команду:

streamlit run helloworld.py

Вуаля, вы должны увидеть простое приложение в своем браузере по адресу localhost:8501, которое позволит вам двигать слайдер для выбора числа и видеть результат возведения этого числа в квадрат.

Это было достаточно просто. В приложении выше мы использовали две функции из Streamlit:

  • Виджет st.slider, который мы можем сдвигать, чтобы изменять вывод веб-приложения
  • И универсальную команду st.write. Я в восторге от того, как она может писать все что угодно, включая графики, датафреймы и обыкновенный текст. Но мы еще поговорим об этом позже.

Важно: Помните, что каждый раз, когда мы меняем значение в виджете, все приложение перезапускается целиком.


Виджеты Streamlit

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

1. Слайдер

streamlit.slider(label, min_value=None, max_value=None, value=None, step=None, format=None)

Мы уже видели st.slider в действии. Он может быть использован с указанием минимального и максимального значения, а также шага для получения входящих значений в заданном диапазоне.

2. Ввод текста

st.text_input — это самый простой способ получить на вход текст от пользователя — будь это какой-то URL или текст для анализа его тональности. Нужно только передать функции название текстового окна.

import streamlit as st
url = st.text_input('Enter URL')
st.write('The Entered URL is', url)

Так будет выглядеть получившееся приложение:

Совет: Вы можете просто изменить файл helloworld.py и обновить браузер. Я обычно работаю таким образом: открываю и изменяю файл в Sublime Text и наблюдаю за изменениями в браузере расположенном в рядом с окном редактора.

3. Чекбокс

Один из вариантов использования чекбоксов — это показывать или прятать определенную часть приложения. Или, например, чекбокс может использоваться для выбора булевозначного параметра для функции. st.checkbox()использует только один аргумент — метку виджета. 

В этом приложении чекбокс используется для переключения условного оператора:

import streamlit as st
import pandas as pd
import numpy as np
df = pd.read_csv("football_data.csv")
if st.checkbox('Show dataframe'):
   st.write(df)

4. Выпадающий список

Мы можем использовать st.selectbox для выбора из списка. Обычно эта функция используется для создания выпадающего списка, который позволяет выбрать значение.

import streamlit as st
import pandas as pd
import numpy as np
df = pd.read_csv("football_data.csv")
option = st.selectbox(
   'Which Club do you like best?',
    df['Club'].unique())
'You selected: ', option

5. Выбор нескольких значений

Мы также можем выбрать несколько значений из выпадающего списка. Для этого можно использовать st.multiselect, которая сохранит несколько выбранных значений в виде списка в переменную options:

import streamlit as st
import pandas as pd
import numpy as np
df = pd.read_csv("football_data.csv")
options = st.multiselect(
'What are your favorite clubs?', df['Club'].unique())
st.write('You selected:', options)

Пошаговое создание простого приложения

Вот мы и разобрали самые важные виджеты. Теперь давайте создадим простое приложение с использованием нескольких из них.

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

import streamlit as st
import pandas as pd
import numpy as np
df = pd.read_csv("football_data.csv")
clubs = st.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique())
# Filter dataframe
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
# write dataframe to screen
st.write(new_df)

Получившееся приложение будет выглядеть вот так:

Это было легко. Но результат выглядит достаточно просто, может стоит добавить графиков?

Streamlit на данный момент поддерживает многие библиотеки для построения графиков. Среди них Plotly, Bokeh, Matplotlib, Altair и Vega charts. Кроме того, работает и Plotly Express, хотя это и не указано в документации. Помимо внешних библиотек, в Streamlit встроены и свои нативные типы графиков, например st.line_chart и st.area_chart.

Сейчас мы будем работать с plotly_express. Вот код для нашего простого приложения. Мы используем всего 4 вызова Streamlit, все остальное — это простой Python:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px
df = pd.read_csv("football_data.csv")
clubs = st.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique())
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)
# create figure using plotly express
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')
# Plot!
st.plotly_chart(fig)

Возможные улучшения

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

1. Кэширование

В нашем базовом приложении мы читаем датафрейм pandas снова всякий раз, когда значение изменяется. И хотя это работает с маленькими базами данных как та, которую мы используем сейчас, но это не сработает с big data или если нам понадобится проводить большое количество манипуляций с данными. Давайте используем кэширование через функцию st.cache:

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

@st.cache
def complex_func(a,b):
   DO SOMETHING COMPLEX
# Won't run again and again.
complex_func(a,b)

Когда мы помечаем функцию кэширующим декоратором, всякий раз, когда эта функция вызывается, Streamlit будет проверять входные параметры функции.

Если Streamlit видит эти параметры впервые, он запустит функцию и сохранит результат в локальном кэше.

Когда функция будет вызывана в следующий раз, если эти параметры не изменились, Streamlit будет знать, что выполнение функции можно пропустить — он просто использует результаты из кэша.

2. Сайдбар

В зависимости от ваших предпочтений, вы можете сделать что-то похожее на Rshiny dashboards и переместить свои виджеты в боковую панель, чтобы придать приложению более аккуратный вид. Для этого просто добавьте st.sidebar в код вашего виджета:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px
df = st.cache(pd.read_csv)("football_data.csv")
clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique())
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)
# Create distplot with custom bin_size
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')
# Plot!
st.plotly_chart(fig)

3. Markdown

Мне нравится использовать Markdown. Мне он кажется менее громоздким, чем HTML, и более подходящим для работы в data science. Можем ли мы использовать Markdown в Streamlit-приложении?

И ответ: да, можем. Есть несколько способов это осуществить. На мой взгляд, лучший вариант — это использовать Magic commands. Эти команды позволят вам использовать Markdown точно так же как и простое комментирование. Но вы также можете воспользоваться командой st.markdown.

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px
'''
# Club and Nationality App
This very simple webapp allows you to select and visualize players from certain clubs and certain nationalities.
'''
df = st.cache(pd.read_csv)("football_data.csv")
clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique())
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)
# Create distplot with custom bin_size
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')
'''
### Here is a simple chart between player age and overall
'''
st.plotly_chart(fig)

Финальное демо приложения


Заключение

Streamlit сделал процесс создания приложений значительно проще, и я однозначно рекомендую его к использования.

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

Мне нравятся цветовая гамма и стили, которые разработчики Streamlit используют по умолчанию, плюс мне кажется, Streamlit удобнее в использовании, чем Dash, который я использовал до этого для создания демо. К тому же Streamlit позволяет добавлять аудио и видео в свои приложения.

Отдельный бонус — это то, что Streamlit является бесплатным open source решением, которое работает прямо из коробки. В прошлом мне приходилось обращаться к друзьям-разработчикам для любого изменения в демо или презентации; теперь все это я могу относительно просто проделать сам.

Я не знаю, будут ли Streamlit-приложения хорошо работать в производственной среде, но они отлично подходят для proof of concept и демо. Я планирую продолжить работать со Streamlit, и, учитывая простоту использования и возможности, которые он предоставляет, я думаю, вам тоже стоит об этом задуматься.Вы можете найти код финальной версии приложения здесь.

Оригинал: How to write Web apps using simple Python for Data Scientists?

Перевод: Ухарова Елена

Понравилась статья? Поделить с друзьями:
  • Как написать автобиографию для альтернативной службы
  • Как написать vin если он отсутствует
  • Как написать vbs скрипт
  • Как написать автобиографическую справку
  • Как написать vbs вирус