В данном уроке мы начнем создание веб-приложения на Flask, которое вычисляет частоту словесных пар на основе текста из предоставленной веб-страницы. Это будет первая часть подробного руководства по созданию веб-сайта на Flask.
- Часть 1: Установка локальной среды разработки, запуск приложения на Heroku (данная статья);
- Часть 2: Установка базы данных PostgreSQL вместе с SQLAlchemy и Alembic для обработки миграций;
- Часть 3: Добавление логики бэкенда для парсинга и последующий процесс подсчета слов с веб-страницы через использование модуля Requests, BeautifulSoup и библиотеки Natural Language Toolkit NLTK;
- Часть 4: Имплементация очереди задач в Redis для обработки текста;
- Часть 5: Использование Angular на фронтенде для постоянного взаимодействия с бэкендом, чтобы посмотреть статус запроса;
- Часть 6: Тестирование приложения на Heroku — установка Redis и описание запуска двух процессов (web и worker) на единственном контейнере (Dyno);
- Часть 7: Обновление фронтенда, чтобы сделать его более удобным для пользователей;
- Часть 8: Создание настраиваемой Angular директивы для отображения диаграммы с частотой словесных пар используя JavaScript и D3.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Если вам нужен исходный код приложения из статьи, можете скачать его с репозитория.
Содержание статьи
- Настройка проекта на Flask
- Установка Heroku для работы с Flask
- Рабочий поток Staging/Production
- Файл конфигурации веб-приложения
- Настройка локальной среды
- Настройки Heroku для Flask
Настройка проекта на Flask
Начнем с создания базового веб-приложения «Hello World» на Heroku с двумя средами:
- staging (стейджинг) — предназначенной для разработки и тестирования;
- production (продакшнен) — предназначенной для релиза протестированных версий нашего веб-приложения.
Для основной настройки проекта, вам нужно быть знакомым со следующими инструментами:
- Virtualenv;
- Flask;
- git/Github;
- Heroku (основы).
Сперва настроим рабочую директорию:
1 |
$ mkdir flask-by-example && cd flask-by-example |
Инициализиуем новый git репозиторий внутри нашей рабочей директории:
1 |
$ git init |
Устанавливаем среду окружения для использования в нашем веб-приложении:
1 2 |
$ python3 -m venv env $ source env/bin/activate |
Теперь вы можете увидеть (env)
с левой стороны терминала, это указывает на то, что сейчас вы работаете в виртуальной среде.
Чтобы покинуть виртуальную среду просто выполните в терминале команду
deactivate
и когда захотите продолжить работу над проектом, запуститеsource env/bin/activate
.
Затем нам нужно будет создать базовую структуру для нашего приложения. Создадим следующие файлы в папку "flask-by-example"
:
1 |
$ touch app.py .gitignore README.md requirements.txt |
В итоге, будет создана следующая структура из файлов:
1 2 3 4 |
├── .gitignore ├── app.py ├── README.md └── requirements.txt |
Не забудьте обновить файл .gitignore
из репозитория.
На всякий случай, стоит обновить pip через команду:
1 |
pip install --upgrade pip |
Устанавливаем Flask через pip:
1 |
$ python -m pip install Flask==1.1.2 |
Добавляем установленные библиотеки в наш файл requirements.txt
:
1 |
$ python -m pip freeze > requirements.txt |
Открываем файл app.py
в текстовом редакторе и добавляем следующий код:
1 2 3 4 5 6 7 8 9 10 |
from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "Hello World!" if __name__ == '__main__': app.run() |
Запускаем приложение:
1 |
$ python app.py |
Вы должны увидеть стандартное приложение «Hello World» в действии на http://localhost:5000/. По завершению работы, веб-сервер нужно закрыть через комбинацию CTRL+C
.
Затем нужно настроить Heroku для запуска веб-приложения на нем.
Установка Heroku для работы с Flask
Если вы этого еще не сделали, создайте аккаунт на Heroku, скачайте и установите Heroku Toolbelt и затем в терминале запустите команду для входа на Heroku:
1 |
heroku login |
После удачного входа на Heroku, нужно создать файл Procfile в вашей корневой директории проекта:
1 |
$ touch Procfile |
Добавляем следующую строку в новый созданный файл Procfile:
1 |
web: gunicorn app:app |
Не забудьте добавить модуль gunicorn в файл зависимостей requirments.txt
:
1 2 |
$ python -m pip install gunicorn==20.0.4 $ python -m pip freeze > requirements.txt |
Нам также нужно указать версию Python, чтобы Heroku использовал верный Python Runtime для запуска нашего веб-приложения.
Просто создаем файл под названием runtime.txt
со следующим содержимым:
1 |
python-3.8.5 |
Загрузим наши изменения через git (также можно разместить на Github), затем создаем две новые веб-приложения на Heroku.
Первое веб-приложение для продакшена:
1 |
$ heroku create wordcount-pro-22-08-2020 |
Второе веб-приложение для стейджинга:
1 |
$ heroku create wordcount-stage-22-08-2020 |
Названия из примера уже заняты, поэтому вы должны выбрать свои собственные уникальные названия.
Я предлагаю использовать такой шаблон названия приложения:
1 |
wordcount-pro-DD-MM-YYYY |
- DD — текущий день;
- MM — месяц;
- YYYY — год.
В моем случае это:
- wordcount-pro-22-08-2020;
- wordcount-stage-22-08-2020.
В моем случае был получен вот такой результат в терминале:
1 2 3 4 |
heroku create wordcount-pro-22-08-2020 Creating ⬢ wordcount-pro-22-08-2020... done https://wordcount-pro-22-08-2020.herokuapp.com/ | https://git.heroku.com/wordcount-pro-22-08-2020.git |
1 2 3 4 |
heroku create wordcount-stage-22-08-2020 Creating ⬢ wordcount-stage-22-08-2020... done https://wordcount-stage-22-08-2020.herokuapp.com/ | https://git.heroku.com/wordcount-stage-22-08-2020.git |
Добавим новые приложения в git remote. Не забудьте назвать один remote pro
(для продакшена), а другой stage
(для стейджинга):
1 2 |
git remote add pro https://git.heroku.com/wordcount-pro-22-08-2020.git git remote add stage https://git.heroku.com/wordcount-stage-22-08-2020.git |
Подготавливаем все файлы для комита:
1 2 |
git add -A git commit -m "Initial commit" |
Теперь можно загрузить оба приложения для работы в режиме реального времени на Heroku:
- Для стейджинга:
git push stage master
- Для продакшена:
git push pro master
Вот так выглядит результат в терминале у меня:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
git push pro master Counting objects: 8, done. Delta compression using up to 8 threads. Compressing objects: 100% (5/5), done. Writing objects: 100% (8/8), 1015 bytes | 1015.00 KiB/s, done. Total 8 (delta 0), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Python app detected remote: -----> Installing python-3.8.5 remote: -----> Installing pip 20.1.1, setuptools 47.1.1 and wheel 0.34.2 remote: -----> Installing SQLite3 remote: -----> Installing requirements with pip remote: Collecting click==7.1.2 remote: Downloading click-7.1.2-py2.py3-none-any.whl (82 kB) remote: Collecting Flask==1.1.2 remote: Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB) remote: Collecting gunicorn==20.0.4 remote: Downloading gunicorn-20.0.4-py2.py3-none-any.whl (77 kB) remote: Collecting itsdangerous==1.1.0 remote: Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB) remote: Collecting Jinja2==2.11.2 remote: Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB) remote: Collecting MarkupSafe==1.1.1 remote: Downloading MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl (32 kB) remote: Collecting Werkzeug==1.0.1 remote: Downloading Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB) remote: Installing collected packages: click, MarkupSafe, Jinja2, Werkzeug, itsdangerous, Flask, gunicorn remote: Successfully installed Flask-1.1.2 Jinja2-2.11.2 MarkupSafe-1.1.1 Werkzeug-1.0.1 click-7.1.2 gunicorn-20.0.4 itsdangerous-1.1.0 remote: -----> Discovering process types remote: Procfile declares types -> web remote: remote: -----> Compressing... remote: Done: 47.9M remote: -----> Launching... remote: Released v3 remote: https://wordcount-pro-22-08-2020.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/wordcount-pro-22-08-2020.git * [new branch] master -> master |
После загрузки файлов на Heroku, можно открыть URL веб-приложения в браузере и, если все прошло хорошо, вы увидите «Hello World!».
Рабочий поток создания веб-приложения
Сделаем изменение в нашем веб-приложении и загрузим их только на стейджинге (тестовой версии нашего веб-приложения):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "Привет, мир!" @app.route('/<name>') def hello_name(name): return f"Привет, {name}!" if __name__ == '__main__': app.run() |
Запустите веб-приложение локально и убедитесь, что все работает:
1 |
python app.py |
Попробуйте добавить в какое либо имя после /
в URL, то есть http://localhost:5000/mike.
Попробуем загрузить текущие изменения только для стейджинга, прежде чем загрузить их в продакшен.
Убедитесь, что ваши изменения зафиксированы в git:
1 2 |
git add -A git commit -m "Добавили новый метод hello_name" |
Затем, загружаем все изменения на стейджинг (приложение для предварительного тестирования):
1 |
git push stage master |
У меня получился вот такой вывод:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
Counting objects: 3, done. Delta compression using up to 8 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 460 bytes | 460.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Python app detected remote: -----> No change in requirements detected, installing from cache remote: -----> Installing pip 20.1.1, setuptools 47.1.1 and wheel 0.34.2 remote: -----> Installing SQLite3 remote: -----> Installing requirements with pip remote: -----> Discovering process types remote: Procfile declares types -> web remote: remote: -----> Compressing... remote: Done: 47.9M remote: -----> Launching... remote: Released v4 remote: https://wordcount-stage-22-08-2020.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/wordcount-stage-22-08-2020.git 8453284..253dc75 master -> master |
Теперь при переходу в среду стейджинга вы сможете использовать новый URL, то есть /mike
и увидите Привет, mike!
в зависимости от того, какое имя вы поместили в URL.
В моем случае это:
1 |
https://wordcount-stage-22-08-2020.herokuapp.com/Mike |
Однако, если вы попробуете то же самое на продакшен сайте, вы получите ошибку. Таким образом, мы можем создавать веб-приложения и тестировать их в среде стейджинга, а затем запускать их на продакшен.
Если все хорошо, давайте загрузим изменения и для продакшена:
1 |
git push pro master |
Теперь та же функциональность доступна на продакшен сайте.
Этот разделенный рабочий процесс в виде стейджинг/продакшен позволяет вносить изменения, показывать нововведения клиентам, экспериментировать и так далее. Все делается внутри изолированного сервера, не вызывая каких-либо изменений на рабочем продакшен сайте, который используют пользователи.
Создаем файл конфигурации веб-приложения
Напоследок, нам нужно настроить конфигурации в зависимости от статуса приложения. Зачастую есть вещи, которые будут отличаться в локальных настройках и в настройках стейджинга и продакшена.
Возможно, вы захотите подключиться к разным базам данных, иметь различные ключи от AWS и так далее. Создадим файл конфигурации для работы с разными средами веб-приложения.
Добавим файл config.py
в корень проекта:
1 |
$ touch config.py |
В файле конфигурации мы собираемся позаимствовать кое-что из того, как настраивается конфигурация в Django. У нас будет базовый класс Config
, от которого наследуются другие классы конфигурации. Затем при необходимости мы импортируем соответствующий класс.
Добавьте следующей код в созданный файл config.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import os basedir = os.path.abspath(os.path.dirname(__file__)) class Config(object): DEBUG = False TESTING = False CSRF_ENABLED = True SECRET_KEY = 'this-really-needs-to-be-changed' class ProductionConfig(Config): DEBUG = False class StagingConfig(Config): DEVELOPMENT = True DEBUG = True class DevelopmentConfig(Config): DEVELOPMENT = True DEBUG = True class TestingConfig(Config): TESTING = True |
Мы импортировали модуль os и затем создали переменную basedir
значение которой является полным путем к файлу config.py
. Затем мы создаем базовый класс Config
с некоторыми основными настройками, которые будут наследовать другие классы.
Теперь мы можем импортировать подходящий нам класс с конфигурациями, в зависимости от статуса нашего веб-приложения. Мы можем использовать переменные среды для выбора настроек, которые будут использоваться в зависимости от среды нашего веб-приложения, которая может быть:
- локальной на нашем компьютере;
- стейджингом (приложение только для тестирования);
- продакшеном (рабочее приложение для пользователей).
Flask: Настройка локальной среды
Для настройки нашего веб-приложения с индивидуальными переменными в зависимости от среды, мы будем использовать модуль autoenv.
Этот модуль позволяет создавать команды, которые будут запускаться каждый раз когда мы заходим в папку нашего приложения. Для того чтобы это реализовать, нам нужно установить модуль autoenv глобально т.е. для всей системы.
Сначала выходим из виртуальной среды в терминале, устанавливаем глобально модуль autoenv
и создаем файл .env
:
1 2 3 |
$ deactivate $ pip install autoenv==1.0.0 $ touch .env |
В файле .env
добавим следующее содержимое:
1 2 |
source env/bin/activate export APP_SETTINGS="config.DevelopmentConfig" |
Выполняем следующие команды в терминале для изменения и обновления файла ~/.bashrc
:
1 2 |
$ echo "source `which activate.sh`" >> ~/.bashrc $ source ~/.bashrc |
Теперь при переходе в данную папку, виртуальная среда автоматически запустится и объявится переменная APP_SETTINGS
.
Настройки Heroku для Flask
Аналогичным образом мы настроим переменные на Heroku.
Для стейджинга запустим следующую команду:
1 |
$ heroku config:set APP_SETTINGS=config.StagingConfig --remote stage |
Полученный ответ:
1 2 |
Setting APP_SETTINGS and restarting ⬢ wordcount-stage-22-08-2020... done, v5 APP_SETTINGS: config.StagingConfig |
Для продакшена:
1 |
$ heroku config:set APP_SETTINGS=config.ProductionConfig --remote pro |
Полученный ответ:
1 2 |
Setting APP_SETTINGS and restarting ⬢ wordcount-pro-22-08-2020... done, v5 APP_SETTINGS: config.ProductionConfig |
Не забудьте проверить, правильно ли работают наши изменения. Обновите содержимое файла app.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import os from flask import Flask app = Flask(__name__) app.config.from_object(os.environ['APP_SETTINGS']) print(os.environ['APP_SETTINGS']) @app.route('/') def hello(): return "Hello World!" @app.route('/<name>') def hello_name(name): return "Hello {}!".format(name) if __name__ == '__main__': app.run() |
Мы импортировали модуль os
и использовали метод os.environ
для импорта соответствующей переменной APP_SETTINGS
, в зависимости от нашей среды. Затем мы настраиваем конфигурацию в нашем приложении с помощью метода app.config.from_object
.
Нам остается только зафиксировать изменения и загрузить их на стейджинг и продакшен (и Github, если он у вас настроен).
1 2 |
git add -A git commit -m "Настройки среды" |
Затем загружаем изменения:
1 2 |
git push stage master git push pro master |
Если вы хотите проверить переменную среды, чтобы убедиться, что она определяет правильную среду, добавьте такой вывод в app.py
:
1 |
print(os.environ['APP_SETTINGS']) |
Теперь при запуске приложения, будет показаны текущие настройки конфигурации:
Локально:
1 2 |
$ python app.py config.DevelopmentConfig |
Стейджинг:
1 2 3 |
$ heroku run python app.py --app wordcount-stage-22-08-2020 Running python app.py on wordcount-stage... up, run.7699 config.StagingConfig |
Продакшен:
1 2 3 |
$ heroku run python app.py --app wordcount-pro-22-08-2020 Running python app.py on wordcount-pro... up, run.8934 config.ProductionConfig |
Не забудьте удалить print(os.environ['APP_SETTINGS'])
по завершению тестирования.
Заключение
Завершив настройку, мы приступим к созданию функции подсчета слов для нашего веб-приложения. Попутно мы создадим очередь задач, чтобы настроить фоновую обработку для части подсчета слов, а также углубимся в настройки Heroku, настроив конфигурацию и миграции для базы данных, которую мы будем использовать для хранения результатов подсчета слов.
Удачи!
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»