Database
 sql >> Base de Dados >  >> RDS >> Database

Flask by Example – Configurando Postgres, SQLAlchemy e Alembic


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.
  1. Parte um:configurar um ambiente de desenvolvimento local e, em seguida, implantar um ambiente de preparação e de produção no Heroku.
  2. Parte Dois:Configure um banco de dados PostgreSQL junto com SQLAlchemy e Alembic para lidar com migrações. (atual )
  3. 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).
  4. Parte quatro:implementar uma fila de tarefas do Redis para lidar com o processamento de texto.
  5. 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.
  6. 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.
  7. Parte sete:atualize o front-end para torná-lo mais fácil de usar.
  8. 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 o psycopg2-binary em vez de psycopg2 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 substituir wordcount-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 o upgrade , não o init ou migrate 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.
  1. 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
  2. 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 no DATABASE_URL recém-criado variável de ambiente.
  3. 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.