Nesta parte, vamos configurar um banco de dados Postgres para armazenar os resultados de nossa contagem de palavras, bem como SQLAlchemy, um Object Relational Mapper e Alembic para lidar com migrações de banco de dados.
Bônus grátis: Clique aqui para obter acesso a um tutorial em vídeo gratuito do Flask + Python que mostra como criar o aplicativo Web Flask, passo a passo.
Atualizações:
- 02/09/2020:atualizado para o Python versão 3.8.1, bem como as versões mais recentes do Psycopg2, Flask-SQLAlchemy e Flask-Migrate. Veja abaixo para detalhes. Instale e use explicitamente o Flask-Script devido à alteração da interface interna do Flask-Migrate.
- 22/03/2016:atualizado para o Python versão 3.5.1, bem como as versões mais recentes do Psycopg2, Flask-SQLAlchemy e Flask-Migrate. Veja abaixo os detalhes.
- 22/02/2015:Adicionado suporte para Python 3.
Lembre-se:Aqui está o que estamos construindo - Um aplicativo Flask que calcula pares de frequência de palavras com base no texto de um determinado URL.
- Parte um:configurar um ambiente de desenvolvimento local e, em seguida, implantar um ambiente de preparação e de produção no Heroku.
- Parte Dois:Configure um banco de dados PostgreSQL junto com SQLAlchemy e Alembic para lidar com migrações. (atual )
- Parte três:adicione a lógica de back-end para extrair e, em seguida, processar a contagem de palavras de uma página da Web usando as bibliotecas de solicitações, BeautifulSoup e Natural Language Toolkit (NLTK).
- Parte quatro:implementar uma fila de tarefas do Redis para lidar com o processamento de texto.
- Parte cinco:configure o Angular no front-end para pesquisar continuamente o back-end para ver se o processamento da solicitação foi concluído.
- Parte seis:enviar para o servidor de teste no Heroku - configurando o Redis e detalhando como executar dois processos (web e worker) em um único Dyno.
- Parte sete:atualize o front-end para torná-lo mais fácil de usar.
- Parte oito:crie uma diretiva angular personalizada para exibir um gráfico de distribuição de frequência usando JavaScript e D3.
Precisa do código? Pegue-o no repositório.
Requisitos de instalação
Ferramentas usadas nesta parte:
- PostgreSQL (11.6)
- Psycopg2 (2.8.4) - um adaptador Python para Postgres
- Flask-SQLAlchemy (2.4.1) - Extensão do Flask que fornece suporte a SQLAlchemy
- Flask-Migrate (2.5.2) - extensão que suporta migrações de banco de dados SQLAlchemy via Alembic
Para começar, instale o Postgres em seu computador local, caso ainda não o tenha. Como o Heroku usa o Postgres, será bom desenvolvermos localmente no mesmo banco de dados. Se você não tiver o Postgres instalado, o Postgres.app é uma maneira fácil de começar a funcionar para usuários do Mac OS X. Consulte a página de download para mais informações.
Depois de instalar e executar o Postgres, crie um banco de dados chamado
wordcount_dev
para usar como nosso banco de dados de desenvolvimento local:$ psql
# create database wordcount_dev;
CREATE DATABASE
# \q
Para usar nosso banco de dados recém-criado no aplicativo Flask, precisamos instalar algumas coisas:
$ cd flask-by-example
cd
entrar no diretório deve ativar o ambiente virtual e definir as variáveis de ambiente encontradas no.env
file via autoenv, que configuramos na parte 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
Se você estiver no OS X e tiver problemas para instalar o psycopg2, confira este artigo do Stack Overflow.
Talvez seja necessário instalar opsycopg2-binary
em vez depsycopg2
se sua instalação falhar.
Atualizar configuração
Adicionar
SQLALCHEMY_DATABASE_URI
campo para o Config()
classe em seu config.py para definir seu aplicativo para usar o banco de dados recém-criado em desenvolvimento (local), preparação e produção:import os
class Config(object):
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
Seu config.py arquivo agora deve ficar assim:
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
Agora, quando nossa configuração for carregada em nosso aplicativo, o banco de dados apropriado também será conectado a ele.
Semelhante a como adicionamos uma variável de ambiente na última postagem, adicionaremos um
DATABASE_URL
variável. Execute isso no terminal:$ export DATABASE_URL="postgresql:///wordcount_dev"
E, em seguida, adicione essa linha em seu .env Arquivo.
Em seu app.py importe o arquivo SQLAlchemy e conecte-se ao banco de dados:
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()
Modelo de dados
Configure um modelo básico adicionando um models.py Arquivo:
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)
Aqui criamos uma tabela para armazenar os resultados da contagem de palavras.
Primeiro importamos a conexão de banco de dados que criamos em nosso app.py bem como JSON dos dialetos PostgreSQL do SQLAlchemy. As colunas JSON são relativamente novas no Postgres e não estão disponíveis em todos os bancos de dados suportados pelo SQLAlchemy, portanto, precisamos importá-las especificamente.
Em seguida, criamos um
Result()
class e atribuí a ela um nome de tabela de results
. Em seguida, definimos os atributos que queremos armazenar para um resultado- - o
id
do resultado que armazenamos - o
url
de onde contamos as palavras - uma lista completa de palavras que contamos
- uma lista de palavras que contamos menos palavras de parada (mais sobre isso depois)
Em seguida, criamos um
__init__()
método que será executado na primeira vez que criarmos um novo resultado e, finalmente, um __repr__()
método para representar o objeto quando o consultamos. Migração local
Vamos usar o Alembic, que faz parte do Flask-Migrate, para gerenciar migrações de banco de dados para atualizar o esquema de um banco de dados.
Observação: Flask-Migrate faz uso da nova ferramenta CLI do Flasks. No entanto, este artigo usa a interface fornecida pelo Flask-Script, que foi usada anteriormente pelo Flask-Migrate. Para usá-lo, você precisa instalá-lo via:$ python -m pip install Flask-Script==2.0.6 $ python -m pip freeze > requirements.txt
Crie um novo arquivo chamado 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()
Para usar o Flask-Migrate, importamos o
Manager
bem como Migrate
e MigrateCommand
para o nosso manage.py Arquivo. Também importamos app
e db
para que tenhamos acesso a eles de dentro do script. Primeiro, definimos nossa configuração para que nosso ambiente - com base na variável de ambiente - crie uma instância de migração, com
app
e db
como os argumentos e configure um manager
comando para inicializar um Manager
instância para nosso aplicativo. Por fim, adicionamos o db
comando para o manager
para que possamos executar as migrações a partir da linha de comando. Para executar as migrações inicialize o 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.
Após executar a inicialização do banco de dados, você verá uma nova pasta chamada “migrations” no projeto. Isso mantém a configuração necessária para o Alembic executar migrações no projeto. Dentro de “migrations” você verá que há uma pasta chamada “versions”, que conterá os scripts de migração à medida que forem criados.
Vamos criar nossa primeira migração executando o
migrate
comando. $ 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
Agora você notará que na pasta “versions” há um arquivo de migração. Este arquivo é gerado automaticamente pelo Alembic com base no modelo. Você mesmo pode gerar (ou editar) este arquivo; no entanto, para a maioria dos casos, o arquivo gerado automaticamente serve.
Agora vamos aplicar as atualizações ao banco de dados usando o
db upgrade
comando:$ 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
O banco de dados agora está pronto para usarmos em nosso aplicativo:
$ 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)
Migração Remota
Por fim, vamos aplicar as migrações aos bancos de dados no Heroku. Primeiro, porém, precisamos adicionar os detalhes dos bancos de dados de preparo e produção ao config.py Arquivo.
Para verificar se temos um banco de dados configurado no servidor de teste, execute:
$ heroku config --app wordcount-stage
=== wordcount-stage Config Vars
APP_SETTINGS: config.StagingConfig
Certifique-se de substituirwordcount-stage
com o nome do seu aplicativo de teste.
Como não vemos uma variável de ambiente de banco de dados, precisamos adicionar o complemento Postgres ao servidor de teste. Para isso, execute o seguinte comando:
$ 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
é o nível gratuito do complemento Heroku Postgres.
Agora, quando executamos
heroku config --app wordcount-stage
novamente, devemos ver as configurações de conexão para o banco de dados:=== 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
Em seguida, precisamos confirmar as alterações que você fez no git e enviar para seu servidor de teste:
$ git push stage master
Execute as migrações que criamos para migrar nosso banco de dados de teste usando o
heroku run
comando:$ 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
Observe como executamos apenas oupgrade
, não oinit
oumigrate
comandos como antes. Já temos nosso arquivo de migração configurado e pronto para uso; só precisamos aplicá-lo no banco de dados Heroku.
Vamos agora fazer o mesmo para a produção.
- Configure um banco de dados para seu aplicativo de produção no Heroku, assim como você fez para o staging:
heroku addons:create heroku-postgresql:hobby-dev --app wordcount-pro
- Envie suas alterações para seu site de produção:
git push pro master
Observe como você não precisa fazer nenhuma alteração no arquivo de configuração - ele está configurando o banco de dados com base noDATABASE_URL
recém-criado variável de ambiente. - Aplicar as migrações:
heroku run python manage.py db upgrade --app wordcount-pro
Agora, nossos sites de preparação e produção têm seus bancos de dados configurados e migrados - e prontos para uso!
Ao aplicar uma nova migração ao banco de dados de produção, pode haver tempo de inatividade. Se isso for um problema, você pode configurar a replicação do banco de dados adicionando um banco de dados “seguidor” (comumente conhecido como escravo). Para saber mais sobre isso, confira a documentação oficial do Heroku.
Conclusão
É isso para a parte 2. Se você quiser se aprofundar no Flask, confira nossa série de vídeos:
Bônus grátis: Clique aqui para obter acesso a um tutorial em vídeo gratuito do Flask + Python que mostra como criar o aplicativo Web Flask, passo a passo.
Na Parte 3, vamos construir a funcionalidade de contagem de palavras e enviá-la para uma fila de tarefas para lidar com o processamento de contagem de palavras em execução mais longa.
Vejo você na próxima vez. Saúde!
Esta é uma colaboração entre Cam Linke, cofundador da Startup Edmonton, e o pessoal da Real Python.