Оглавление
- Требования к установке
- Обновить конфигурацию
- Модель данных
- Местная миграция
- Удаленная миграция
- Заключение
В этой части мы собираемся настроить базу данных Postgres для хранения результатов подсчета слов, а также SQLAlchemy, Object Relational Mapper и Alembic для обработки миграции базы данных.
Бесплатный бонус: нажмите здесь, чтобы получить доступ к бесплатному видеоуроку Flask + Python , в котором шаг за шагом показано, как создать веб-приложение Flask.
Обновления:
09.02.2020: Обновлен до версии Python 3.8.1, а также до последних версий Psycopg2, Flask-SQLAlchemy и Flask-Migrate. Подробнее см. Ниже . Явно установите и используйте Flask-Script в связи с изменением внутреннего интерфейса Flask-Migrate.
22.03.2016: Обновлен до версии Python 3.5.1, а также до последних версий Psycopg2, Flask-SQLAlchemy и Flask-Migrate. Подробнее см. Ниже .
22.02.2015: Добавлена поддержка Python 3.
Помните: вот что мы создаем - приложение Flask, которое вычисляет пары частотность слова на основе текста из заданного URL-адреса.
Часть первая : настройте локальную среду разработки, а затем разверните как промежуточную, так и производственную среду на Heroku.Часть вторая: настройте базу данных PostgreSQL вместе с SQLAlchemy и Alembic для обработки миграций. ( текущий )
Часть третья : добавьте внутреннюю логику для очистки, а затем обработки количества слов с веб-страницы с помощью библиотек запросов, BeautifulSoup и Natural Language Toolkit (NLTK).
Часть четвертая : реализация очереди задач Redis для обработки текста.
Часть пятая : настройте Angular во внешнем интерфейсе, чтобы постоянно опрашивать серверную часть, чтобы узнать, обработан ли запрос.
Часть шестая : Отправка на промежуточный сервер на Heroku - настройка Redis и подробное описание того, как запустить два процесса (веб-сайт и рабочий) на одном Dyno.
Часть седьмая : Обновите интерфейс, чтобы сделать его более удобным для пользователя.
Часть восьмая : Создайте настраиваемую директиву Angular для отображения диаграммы частотного распределения с использованием JavaScript и D3.
Требования к установке
Инструменты, используемые в этой части:
PostgreSQL ( 11.6 )
Psycopg2 ( 2.8.4 ) - адаптер Python для Postgres
Flask-SQLAlchemy ( 2.4.1 ) - расширение Flask, обеспечивающее поддержку SQLAlchemy.
Flask-Migrate ( 2.5.2 ) - расширение, которое поддерживает миграцию базы данных SQLAlchemy через Alembic
Для начала установите Postgres на свой локальный компьютер, если у вас его еще нет. Поскольку Heroku использует Postgres, нам будет хорошо разрабатывать локально в той же базе данных. Если у вас не установлен Postgres, Postgres.app - это простой способ начать работу для пользователей Mac OS X. Посетите страницу загрузки для получения дополнительной информации.
После установки и запуска Postgres создайте базу данных, которая wordcount_devбудет использоваться в качестве нашей локальной базы данных для разработки:
$ psql # create database wordcount_dev; CREATE DATABASE # \q
Чтобы использовать нашу недавно созданную базу данных в приложении Flask, нам нужно установить несколько вещей:
$ cd flask-by-example
cdВход в каталог должен активировать виртуальную среду и установить переменные среды, найденные в .envфайле, с помощью autoenv , который мы установили в части 1 .
$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2 $ python -m pip freeze > requirements.txt
Если вы используете OS X и у вас возникли проблемы с установкой psycopg2, ознакомьтесь с этой статьей о переполнении стека.
Вам может потребоваться установить psycopg2-binaryвместо, psycopg2если ваша установка не удалась.
Обновить конфигурацию
Добавьте SQLALCHEMY_DATABASE_URIполе к Config()классу в файле config.py, чтобы настроить приложение для использования вновь созданной базы данных при разработке (локальной), промежуточной и производственной:
import os class Config(object): ... SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
Ваш файл config.py теперь должен выглядеть так:
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' SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL'] class ProductionConfig(Config): DEBUG = False class StagingConfig(Config): DEVELOPMENT = True DEBUG = True class DevelopmentConfig(Config): DEVELOPMENT = True DEBUG = True class TestingConfig(Config): TESTING = True
Теперь, когда наша конфигурация загружена в наше приложение, к ней также будет подключена соответствующая база данных.
Подобно тому, как мы добавляли переменную среды в предыдущем посте, мы собираемся добавить DATABASE_URLпеременную. Запустите это в терминале:
$ export DATABASE_URL="postgresql:///wordcount_dev"
А затем добавьте эту строку в свой файл .env .
В вашем файле app.py импортируйте SQLAlchemy и подключитесь к базе данных:
from flask import Flask from flask_sqlalchemy import SQLAlchemy import os app = Flask(__name__) app.config.from_object(os.environ['APP_SETTINGS']) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) from models import Result @app.route('/') def hello(): return "Hello World!" @app.route('/<name>') def hello_name(name): return "Hello {}!".format(name) if __name__ == '__main__': app.run()
Модель данных
Настройте базовую модель, добавив файл models.py :
from app import db from sqlalchemy.dialects.postgresql import JSON class Result(db.Model): __tablename__ = 'results' id = db.Column(db.Integer, primary_key=True) url = db.Column(db.String()) result_all = db.Column(JSON) result_no_stop_words = db.Column(JSON) def __init__(self, url, result_all, result_no_stop_words): self.url = url self.result_all = result_all self.result_no_stop_words = result_no_stop_words def __repr__(self): return '<id {}>'.format(self.id)
Здесь мы создали таблицу для хранения результатов подсчета слов.
Сначала мы импортируем соединение с базой данных, которое мы создали в нашем файле app.py, а также JSON из диалектов PostgreSQL SQLAlchemy . Столбцы JSON довольно новы для Postgres и доступны не во всех базах данных, поддерживаемых SQLAlchemy, поэтому нам нужно импортировать их специально.
Затем мы создали Result()класс и присвоили ему имя таблицы results. Затем мы устанавливаем атрибуты, которые хотим сохранить для результата -
- idрезультата мы сохранили
- то, urlчто мы посчитали слова из
- полный список слов, которые мы посчитали
- список слов, которые мы посчитали за вычетом стоп-слов (подробнее об этом позже)
Затем мы создали __init__()метод, который будет запускаться при первом создании нового результата, и, наконец, __repr__()метод для представления объекта, когда мы его запрашиваем.
Местная миграция
Мы собираемся использовать Alembic , который является частью Flask-Migrate , для управления миграциями базы данных для обновления схемы базы данных.
Примечание. Flask-Migrate использует новый инструмент командной строки Flasks. Однако в этой статье используется интерфейс, предоставляемый Flask-Script , который ранее использовался Flask-Migrate. Чтобы использовать его, вам необходимо установить его через:
$ python -m pip install Flask-Script==2.0.6 $ python -m pip freeze > requirements.txt
Создайте новый файл с именем manage.py :
import os from flask_script import Manager from flask_migrate import Migrate, MigrateCommand from app import app, db app.config.from_object(os.environ['APP_SETTINGS']) migrate = Migrate(app, db) manager = Manager(app) manager.add_command('db', MigrateCommand) if __name__ == '__main__': manager.run()
Чтобы использовать Flask-Migrate, мы импортировали Managerтакже Migrateи MigrateCommandв наш файл manage.py . Мы также импортировали, appи dbпоэтому у нас есть доступ к ним из сценария.
Во-первых, мы настраиваем нашу конфигурацию так, чтобы наша среда - на основе переменной среды - создавала экземпляр миграции с аргументами appи dbв качестве аргументов и настраивала managerкоманду для инициализации Managerэкземпляра для нашего приложения. Наконец, мы добавили dbкоманду в managerфайл, чтобы мы могли запускать миграции из командной строки.
Для запуска миграции инициализируйте Alembic:
$ python manage.py db init Creating directory /flask-by-example/migrations ... done Creating directory /flask-by-example/migrations/versions ... done Generating /flask-by-example/migrations/alembic.ini ... done Generating /flask-by-example/migrations/env.py ... done Generating /flask-by-example/migrations/README ... done Generating /flask-by-example/migrations/script.py.mako ... done Please edit configuration/connection/logging settings in '/flask-by-example/migrations/alembic.ini' before proceeding.
После запуска инициализации базы данных вы увидите в проекте новую папку с именем «migrations». Это содержит настройку, необходимую Alembic для выполнения миграций проекта. Вы увидите, что внутри «миграции» есть папка с именем «версии», в которой будут храниться сценарии миграции по мере их создания.
Давайте создадим нашу первую миграцию, выполнив migrateкоманду.
$ python manage.py db migrate INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. INFO [alembic.autogenerate.compare] Detected added table 'results' Generating /flask-by-example/migrations/versions/63dba2060f71_.py ... done
Теперь вы заметите, что в папке «версии» есть файл миграции. Этот файл автоматически создается Alembic на основе модели. Вы можете самостоятельно сгенерировать (или отредактировать) этот файл; однако в большинстве случаев подойдет автоматически созданный файл.
Теперь мы применим обновления к базе данных с помощью db upgradeкоманды:
$ python manage.py db upgrade INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. INFO [alembic.runtime.migration] Running upgrade -> 63dba2060f71, empty message
База данных теперь готова для использования в нашем приложении:
$ psql # \c wordcount_dev You are now connected to database "wordcount_dev" as user "michaelherman". # \dt List of relations Schema | Name | Type | Owner --------+-----------------+-------+--------------- public | alembic_version | table | michaelherman public | results | table | michaelherman (2 rows) # \d results Table "public.results" Column | Type | Modifiers ----------------------+-------------------+------------------------------------------------------ id | integer | not null default nextval('results_id_seq'::regclass) url | character varying | result_all | json | result_no_stop_words | json | Indexes: "results_pkey" PRIMARY KEY, btree (id)
Удаленная миграция
Наконец, давайте применим миграции к базам данных на Heroku. Однако сначала нам нужно добавить сведения о промежуточной и производственной базах данных в файл config.py .
Чтобы проверить, настроена ли у нас база данных на промежуточном сервере, запустите:
$ heroku config --app wordcount-stage === wordcount-stage Config Vars APP_SETTINGS: config.StagingConfig
Не забудьте заменить wordcount-stageна имя вашего промежуточного приложения.
Поскольку мы не видим переменную среды базы данных, нам нужно добавить надстройку Postgres на промежуточный сервер. Для этого выполните следующую команду:
$ heroku addons:create heroku-postgresql:hobby-dev --app wordcount-stage Creating postgresql-cubic-86416... done, (free) Adding postgresql-cubic-86416 to wordcount-stage... done Setting DATABASE_URL and restarting wordcount-stage... done, v8 Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pg:copy Use `heroku addons:docs heroku-postgresql` to view documentation.
hobby-devэто бесплатный уровень аддона Heroku Postgres.
Теперь, когда мы heroku config --app wordcount-stageснова запустим, мы должны увидеть настройки подключения для базы данных:
=== wordcount-stage Config Vars APP_SETTINGS: config.StagingConfig DATABASE_URL: postgres://azrqiefezenfrg::5432/d2kio2ubc804p7
Затем нам нужно зафиксировать изменения, которые вы внесли в git, и отправить на промежуточный сервер:
$ git push stage master
Запустите миграции, которые мы создали для миграции нашей промежуточной базы данных, используя heroku runкоманду:
$ heroku run python manage.py db upgrade --app wordcount-stage Running python manage.py db upgrade on wordcount-stage... up, run.5677 INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. INFO [alembic.runtime.migration] Running upgrade -> 63dba2060f71, empty message
Обратите внимание , как мы только запускали upgrade, не initили migrateкоманды , как и раньше. Наш файл миграции уже настроен и готов к работе; нам просто нужно применить его к базе данных Heroku.
Теперь сделаем то же самое для продакшена.
- Настройте базу данных для своего производственного приложения на Heroku, как вы это делали для постановки: heroku addons:create heroku-postgresql:hobby-dev --app wordcount-pro
- Отправьте свои изменения на рабочий сайт: git push pro masterобратите внимание, что вам не нужно вносить какие-либо изменения в файл конфигурации - он устанавливает базу данных на основе вновь созданной DATABASE_URLпеременной среды.
- Примените миграции: heroku run python manage.py db upgrade --app wordcount-pro
Теперь и на нашем промежуточном, и на производственном сайтах настроены базы данных, они перенесены - и готовы к работе!
Когда вы применяете новую миграцию к производственной базе данных, может возникнуть время простоя. Если это проблема, вы можете настроить репликацию базы данных, добавив «ведомую» базу данных. Подробнее об этом читайте в официальной документации Heroku .
Заключение
Это все, что касается части 2. Если вы хотите глубже изучить Flask, посмотрите нашу сопутствующую серию видео:
Бесплатный бонус: нажмите здесь, чтобы получить доступ к бесплатному видеоуроку Flask + Python , в котором шаг за шагом показано, как создать веб-приложение Flask.
В части 3 мы собираемся создать функцию подсчета слов и отправить ее в очередь задач, чтобы иметь дело с более длительной обработкой подсчета слов.
Увидимся в следующий раз. Ваше здоровье!