sql >> Databasteknik >  >> RDS >> Database

Kolv efter exempel – Konfigurera Postgres, SQLAlchemy och Alembic

I den här delen kommer vi att skapa en Postgres-databas för att lagra resultaten av våra ordräkningar samt SQLAlchemy, en Object Relational Mapper och Alembic för att hantera databasmigreringar.

Gratis bonus: Klicka här för att få tillgång till en gratis självstudievideo för Flask + Python som visar hur du bygger en webbapp för Flask, steg för steg.

Uppdateringar:

  • 02/09/2020:Uppgraderad till Python version 3.8.1 samt de senaste versionerna av Psycopg2, Flask-SQLAlchemy och Flask-Migrate. Se nedan för detaljer. Installera och använd Flask-Script explicit på grund av förändring av det interna gränssnittet för Flask-Migrate.
  • 03/22/2016:Uppgraderad till Python version 3.5.1 samt de senaste versionerna av Psycopg2, Flask-SQLAlchemy och Flask-Migrate. Se nedan för mer information.
  • 02/22/2015:Lade till stöd för Python 3.

Kom ihåg:Det här är vad vi bygger - En Flask-app som beräknar ord-frekvenspar baserat på texten från en given webbadress.

  1. Del ett:Skapa en lokal utvecklingsmiljö och distribuera sedan både en iscensättning och en produktionsmiljö på Heroku.
  2. Del två:Konfigurera en PostgreSQL-databas tillsammans med SQLAlchemy och Alembic för att hantera migrering. (aktuell )
  3. Del tre:Lägg till back-end-logiken för att skrapa och bearbeta sedan ordantalet från en webbsida med hjälp av biblioteken för begäran, BeautifulSoup och Natural Language Toolkit (NLTK).
  4. Del fyra:Implementera en Redis-uppgiftskö för att hantera textbehandlingen.
  5. Del fem:Ställ in Angular på front-end för att kontinuerligt polla back-end för att se om begäran är klar.
  6. Del sex:Push till staging-servern på Heroku - ställ in Redis och beskriver hur man kör två processer (webb och worker) på en enda Dyno.
  7. Del sju:Uppdatera gränssnittet för att göra det mer användarvänligt.
  8. Del åtta:Skapa ett anpassat vinkeldirektiv för att visa ett frekvensfördelningsdiagram med JavaScript och D3.

Behöver du koden? Ta tag i det från arkivet.


Installationskrav

Verktyg som används i denna del:

  • PostgreSQL (11.6)
  • Psycopg2 (2.8.4) - en Python-adapter för Postgres
  • Flask-SQLAlchemy (2.4.1) - Flask-tillägg som ger stöd för SQLAlchemy
  • Flask-Migrate (2.5.2) – tillägg som stöder SQLAlchemy-databasmigrering via Alembic

För att komma igång, installera Postgres på din lokala dator, om du inte redan har det. Eftersom Heroku använder Postgres kommer det att vara bra för oss att utveckla lokalt på samma databas. Om du inte har Postgres installerat är Postgres.app ett enkelt sätt att komma igång för Mac OS X-användare. Se nedladdningssidan för mer information.

När du har Postgres installerat och kört, skapa en databas som heter wordcount_dev att använda som vår lokala utvecklingsdatabas:

$ psql
# create database wordcount_dev;
CREATE DATABASE
# \q

För att kunna använda vår nyskapade databas i Flask-appen måste vi installera några saker:

$ cd flask-by-example

cd ing i katalogen bör aktivera den virtuella miljön och ställa in miljövariablerna som finns i .env fil via autoenv, som vi satte upp i del 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

Om du använder OS X och har problem med att installera psycopg2, kolla in den här Stack Overflow-artikeln.

Du kan behöva installera psycopg2-binary istället för psycopg2 om din installation misslyckas.



Uppdatera konfiguration

Lägg till SQLALCHEMY_DATABASE_URI till Config() klass i din config.py fil för att ställa in din app att använda den nyskapade databasen i utveckling (lokal), iscensättning och produktion:

import os

class Config(object):
    ...
    SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']

Din config.py filen ska nu se ut så här:

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

Nu när vår konfiguration har laddats in i vår app kommer lämplig databas också att kopplas till den.

I likhet med hur vi la till en miljövariabel i förra inlägget, kommer vi att lägga till en DATABASE_URL variabel. Kör detta i terminalen:

$ export DATABASE_URL="postgresql:///wordcount_dev"

Och lägg sedan till den raden i din .env fil.

I din app.py filimportera SQLAlchemy och anslut till databasen:

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()


Datamodell

Ställ in en grundläggande modell genom att lägga till en models.py fil:

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)

Här skapade vi en tabell för att lagra resultaten av ordräkningarna.

Vi importerar först databasanslutningen som vi skapade i vår app.py fil samt JSON från SQLAlchemys PostgreSQL-dialekter. JSON-kolumner är ganska nya för Postgres och är inte tillgängliga i alla databaser som stöds av SQLAlchemy så vi måste importera den specifikt.

Därefter skapade vi en Result() klass och tilldelade den ett tabellnamn med results . Vi ställer sedan in attributen som vi vill lagra för ett resultat-

  • id av resultatet vi lagrade
  • url som vi räknade orden från
  • en fullständig lista över ord som vi räknade
  • en lista med ord som vi räknade minus stoppord (mer om detta senare)

Vi skapade sedan en __init__() metod som körs första gången vi skapar ett nytt resultat och slutligen en __repr__() metod för att representera objektet när vi frågar efter det.



Lokal migrering

Vi kommer att använda Alembic, som är en del av Flask-Migrate, för att hantera databasmigreringar för att uppdatera en databas schema.

Obs! Flask-Migrate använder sig av Flasks nya CLI-verktyg. Den här artikeln använder dock gränssnittet från Flask-Script, som tidigare användes av Flask-Migrate. För att använda det måste du installera det via:

$ python -m pip install Flask-Script==2.0.6
$ python -m pip freeze > requirements.txt

Skapa en ny fil som heter 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()

För att använda Flask-Migrate importerade vi Manager samt Migrate och MigrateCommand till vår manage.py fil. Vi importerade också app och db så vi har tillgång till dem från skriptet.

Först ställer vi in ​​vår konfiguration för att få vår miljö - baserat på miljövariabeln - att skapa en migreringsinstans, med app och db som argument, och ställ in en manager kommando för att initiera en Manager exempel för vår app. Slutligen lade vi till db kommandot till manager så att vi kan köra migreringarna från kommandoraden.

Initiera Alembic:

för att köra migreringarna
$ 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.

När du har kört databasinitieringen kommer du att se en ny mapp som heter "migrationer" i projektet. Detta innehåller den installation som krävs för att Alembic ska kunna köra migreringar mot projektet. Inuti "migrering" kommer du att se att den har en mapp som heter "versioner", som kommer att innehålla migreringsskripten när de skapas.

Låt oss skapa vår första migrering genom att köra migrate kommando.

$ 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

Nu kommer du att märka att det finns en migreringsfil i mappen "versioner". Den här filen är automatiskt genererad av Alembic baserat på modellen. Du kan skapa (eller redigera) den här filen själv; Men i de flesta fall fungerar den automatiskt genererade filen.

Nu kommer vi att tillämpa uppgraderingarna på databasen med db upgrade kommando:

$ 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

Databasen är nu klar för oss att använda i vår app:

$ 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)


Fjärmigrering

Slutligen, låt oss tillämpa migreringarna på databaserna på Heroku. Först måste vi dock lägga till detaljerna om iscensättnings- och produktionsdatabaserna till config.py fil.

För att kontrollera om vi har en databas inställd på staging-servern, kör:

$ heroku config --app wordcount-stage
=== wordcount-stage Config Vars
APP_SETTINGS: config.StagingConfig

Se till att ersätta wordcount-stage med namnet på din iscensättningsapp.

Eftersom vi inte ser en databasmiljövariabel måste vi lägga till Postgres-tillägget till staging-servern. För att göra det, kör följande kommando:

$ 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 är den kostnadsfria nivån för Heroku Postgres-tillägget.

Nu när vi kör heroku config --app wordcount-stage igen bör vi se anslutningsinställningarna för databasen:

=== 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

Därefter måste vi överföra ändringarna som du har gjort i git och push till din staging-server:

$ git push stage master

Kör migreringarna som vi skapade för att migrera vår mellanlagringsdatabas genom att använda heroku run kommando:

$ 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

Lägg märke till hur vi bara körde upgrade , inte init eller migrate kommandon som tidigare. Vi har redan vår migreringsfil konfigurerad och redo att gå; vi behöver bara applicera det mot Heroku-databasen.

Låt oss nu göra samma sak för produktionen.

  1. Sätt upp en databas för din produktionsapp på Heroku, precis som du gjorde för iscensättning:heroku addons:create heroku-postgresql:hobby-dev --app wordcount-pro
  2. Överför dina ändringar till din produktionsplats:git push pro master Lägg märke till hur du inte behöver göra några ändringar i konfigurationsfilen - det är att ställa in databasen baserat på den nyskapade DATABASE_URL miljövariabel.
  3. Använd migreringarna:heroku run python manage.py db upgrade --app wordcount-pro

Nu har både våra iscensättnings- och produktionsplatser sina databaser konfigurerade och migrerade - och redo att börja!

När du tillämpar en ny migrering till produktionsdatabasen kan det bli stilleståndstid. Om detta är ett problem kan du ställa in databasreplikering genom att lägga till en "följare" (allmänt känd som en slav) databas. För mer om detta, kolla in den officiella Heroku-dokumentationen.



Slutsats

Det var allt för del 2. Om du vill gräva djupare i Flask, kolla in vår medföljande videoserie:

Gratis bonus: Klicka här för att få tillgång till en gratis självstudiekurs för Flask + Python som visar hur du bygger en webbapp för Flask, steg för steg.

I del 3 kommer vi att bygga ordräkningsfunktionen och skicka den till en uppgiftskö för att hantera den längre pågående ordräkningsbehandlingen.

Vi ses nästa gång. Skål!

Detta är ett samarbete mellan Cam Linke, medgrundare av Startup Edmonton, och folket på Real Python.



  1. Hur man genererar drop Unique Constraint-skript i SQL Server Database - SQL Server / TSQL Tutorial Del 99

  2. array_agg för matristyper

  3. Definiera en variabel inom select och använd den inom samma select

  4. Lägg till ny RAC-instans manuellt