В тази част ще настроим база данни на Postgres, за да съхраняваме резултатите от нашето броене на думи, както и SQLAlchemy, Object Relational Mapper и Alembic за обработка на миграции на база данни.
Безплатен бонус: Щракнете тук, за да получите достъп до безплатен видеоурок за Flask + Python, който ви показва как да създадете уеб приложение за Flask, стъпка по стъпка.
Актуализации:
- 02/09/2020:Надстроен до Python версия 3.8.1, както и най-новите версии на Psycopg2, Flask-SQLAlchemy и Flask-Migrate. Вижте по-долу за подробности. Инсталирайте и използвайте изрично Flask-Script поради промяна на вътрешния интерфейс на Flask-Migrate.
- 22.03.2016 г.:Надстроен до версия 3.5.1 на Python, както и най-новите версии на 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.
- Част седма:Актуализирайте предния край, за да го направите по-удобен за потребителя.
- Част осма:Създайте персонализирана ъглова директива за показване на диаграма на честотно разпределение с помощта на 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 използва новия инструмент за CLI Flask. Тази статия обаче използва интерфейса, предоставен от 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.
След като стартирате инициализацията на базата данни, ще видите нова папка, наречена „миграции“ в проекта. Това поддържа настройката, необходима на 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:Zti5fjSyeyFgoc-U-yXnPrXHQv@ec2-54-225-151-64.compute-1.amazonaws.com: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 ще изградим функционалността за броене на думи и ще я изпратим на опашка със задачи, за да се справим с по-продължителната обработка на броя на думите.
Ще се видим следващия път. Наздраве!
Това е част от сътрудничеството между Cam Linke, съосновател на Startup Edmonton, и хората от Real Python.