sql >> Database >  >> RDS >> Database

Flask by example - Postgres, SQLAlchemy en Alembic instellen

In dit deel gaan we een Postgres-database opzetten om de resultaten van onze woordentellingen op te slaan, evenals SQLAlchemy, een Object Relational Mapper en Alembic om databasemigraties af te handelen.

Gratis bonus: Klik hier om toegang te krijgen tot een gratis Flask + Python-videozelfstudie die u stap voor stap laat zien hoe u de Flask-webapp bouwt.

Updates:

  • 09/02/2020:geüpgraded naar Python-versie 3.8.1 en de nieuwste versies van Psycopg2, Flask-SQLAlchemy en Flask-Migrate. Zie hieronder voor details. Installeer en gebruik Flask-Script expliciet vanwege de wijziging van de interne interface van Flask-Migrate.
  • 22-03-2016:geüpgraded naar Python-versie 3.5.1 en de nieuwste versies van Psycopg2, Flask-SQLAlchemy en Flask-Migrate. Zie hieronder voor details.
  • 22/02/2015:ondersteuning voor Python 3 toegevoegd.

Onthoud:dit is wat we aan het bouwen zijn:een Flask-app die woordfrequentieparen berekent op basis van de tekst van een bepaalde URL.

  1. Deel één:zet een lokale ontwikkelomgeving op en implementeer vervolgens zowel een staging- als een productieomgeving op Heroku.
  2. Deel twee:Stel een PostgreSQL-database samen met SQLAlchemy en Alembic om migraties af te handelen. (huidig )
  3. Deel drie:voeg de back-endlogica toe om het aantal woorden van een webpagina te schrapen en vervolgens te verwerken met behulp van de bibliotheken met verzoeken, BeautifulSoup en Natural Language Toolkit (NLTK).
  4. Deel vier:Implementeer een Redis-taakwachtrij om de tekstverwerking af te handelen.
  5. Deel vijf:stel Angular in aan de front-end om continu de back-end te pollen om te zien of het verzoek is verwerkt.
  6. Deel zes:push naar de staging-server op Heroku - Redis instellen en beschrijven hoe twee processen (web en worker) op een enkele Dyno kunnen worden uitgevoerd.
  7. Deel zeven:werk de front-end bij om deze gebruiksvriendelijker te maken.
  8. Deel acht:maak een aangepaste hoekrichtlijn om een ​​frequentieverdelingsdiagram weer te geven met JavaScript en D3.

Code nodig? Pak het uit de repo.


Installatievereisten

Tools die in dit deel worden gebruikt:

  • PostgreSQL (11,6)
  • Psycopg2 (2.8.4) - een Python-adapter voor Postgres
  • Flask-SQLAlchemy (2.4.1) - Flask-extensie die SQLAlchemy-ondersteuning biedt
  • Flask-Migrate (2.5.2) - extensie die SQLAlchemy databasemigraties via Alembic ondersteunt

Installeer om te beginnen Postgres op uw lokale computer, als u deze nog niet heeft. Aangezien Heroku Postgres gebruikt, is het goed voor ons om lokaal op dezelfde database te ontwikkelen. Als Postgres niet is geïnstalleerd, is Postgres.app een gemakkelijke manier om aan de slag te gaan voor Mac OS X-gebruikers. Raadpleeg de downloadpagina voor meer info.

Zodra Postgres is geïnstalleerd en actief is, maakt u een database met de naam wordcount_dev om te gebruiken als onze lokale ontwikkelingsdatabase:

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

Om onze nieuw aangemaakte database in de Flask-app te gebruiken, moeten we een paar dingen installeren:

$ cd flask-by-example

cd Als u de directory ingaat, moet de virtuele omgeving worden geactiveerd en moeten de omgevingsvariabelen in de .env worden ingesteld bestand via autoenv, dat we in deel 1 hebben ingesteld.

$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2
$ python -m pip freeze > requirements.txt

Als je OS X gebruikt en problemen hebt met het installeren van psycopg2, bekijk dan dit Stack Overflow-artikel.

Mogelijk moet u psycopg2-binary . installeren in plaats van psycopg2 als uw installatie mislukt.



Configuratie bijwerken

SQLALCHEMY_DATABASE_URI toevoegen veld naar de Config() class in uw config.py bestand om uw app in te stellen om de nieuw gemaakte database te gebruiken in ontwikkeling (lokaal), fasering en productie:

import os

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

Uw config.py bestand zou er nu als volgt uit moeten zien:

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

Wanneer onze configuratie nu in onze app wordt geladen, wordt de juiste database er ook mee verbonden.

Vergelijkbaar met hoe we een omgevingsvariabele in de laatste post hebben toegevoegd, gaan we een DATABASE_URL toevoegen variabel. Voer dit uit in de terminal:

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

En voeg dan die regel toe aan je .env bestand.

In uw app.py bestand importeren SQLAlchemy en verbinding maken met de database:

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


Gegevensmodel

Stel een basismodel in door een models.py . toe te voegen bestand:

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)

Hier hebben we een tabel gemaakt om de resultaten van het aantal woorden op te slaan.

We importeren eerst de databaseverbinding die we hebben gemaakt in onze app.py bestand evenals JSON uit de PostgreSQL-dialecten van SQLAlchemy. JSON-kolommen zijn vrij nieuw voor Postgres en zijn niet beschikbaar in elke database die wordt ondersteund door SQLAlchemy, dus we moeten deze specifiek importeren.

Vervolgens hebben we een Result() . gemaakt class en gaf het een tabelnaam van results . Vervolgens stellen we de attributen in die we willen opslaan voor een resultaat-

  • de id van het resultaat dat we hebben opgeslagen
  • de url dat we de woorden telden van
  • een volledige lijst met woorden die we hebben geteld
  • een lijst met woorden die we hebben geteld minus stopwoorden (hierover later meer)

Vervolgens hebben we een __init__() . gemaakt methode die wordt uitgevoerd de eerste keer dat we een nieuw resultaat maken en tot slot een __repr__() methode om het object weer te geven wanneer we ernaar vragen.



Lokale migratie

We gaan Alembic, een onderdeel van Flask-Migrate, gebruiken om databasemigraties te beheren om het schema van een database bij te werken.

Opmerking: Flask-Migrate maakt gebruik van de nieuwe CLI-tool van Flasks. Dit artikel gebruikt echter de interface van Flask-Script, die eerder door Flask-Migrate werd gebruikt. Om het te gebruiken, moet je het installeren via:

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

Maak een nieuw bestand met de naam 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()

Om Flask-Migrate te gebruiken hebben we Manager . geïmporteerd evenals Migrate en MigrateCommand naar onze manage.py het dossier. We hebben ook app geïmporteerd en db dus we hebben er toegang toe vanuit het script.

Eerst hebben we onze configuratie zo ingesteld dat onze omgeving - op basis van de omgevingsvariabele - een migratie-instantie heeft gemaakt, met app en db als de argumenten, en stel een manager in commando om een ​​Manager te initialiseren bijvoorbeeld voor onze app. Ten slotte hebben we de db . toegevoegd commando aan de manager zodat we de migraties vanaf de opdrachtregel kunnen uitvoeren.

Om de migraties uit te voeren, initialiseert u 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.

Nadat u de database-initialisatie hebt uitgevoerd, ziet u een nieuwe map met de naam "migraties" in het project. Dit bevat de instellingen die Alembic nodig heeft om migraties tegen het project uit te voeren. Binnenin "migraties" ziet u dat het een map heeft met de naam "versies", die de migratiescripts zal bevatten zoals ze zijn gemaakt.

Laten we onze eerste migratie maken door de migrate commando.

$ 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 zult u merken dat er in uw map "versies" een migratiebestand is. Dit bestand wordt automatisch gegenereerd door Alembic op basis van het model. U zou dit bestand zelf kunnen genereren (of bewerken); in de meeste gevallen is het automatisch gegenereerde bestand echter voldoende.

Nu passen we de upgrades toe op de database met behulp van de db upgrade commando:

$ 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

De database is nu klaar voor gebruik in onze 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)


Migratie op afstand

Laten we tot slot de migraties toepassen op de databases op Heroku. Maar eerst moeten we de details van de staging- en productiedatabases toevoegen aan de config.py bestand.

Om te controleren of we een database hebben ingesteld op de staging-server:

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

Zorg ervoor dat u wordcount-stage vervangt met de naam van je staging-app.

Omdat we geen database-omgevingsvariabele zien, moeten we de Postgres-add-on toevoegen aan de staging-server. Voer hiervoor de volgende opdracht uit:

$ 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 is de gratis laag van de Heroku Postgres-add-on.

Wanneer we nu heroku config --app wordcount-stage opnieuw zouden we de verbindingsinstellingen voor de database moeten zien:

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

Vervolgens moeten we de wijzigingen die je hebt aangebracht in git en push naar je staging-server doorvoeren:

$ git push stage master

Voer de migraties uit die we hebben gemaakt om onze staging-database te migreren met behulp van de heroku run commando:

$ 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

Merk op hoe we alleen de upgrade hebben uitgevoerd , niet de init of migrate commando's zoals voorheen. We hebben ons migratiebestand al ingesteld en klaar voor gebruik; we hoeven het alleen maar toe te passen op de Heroku-database.

Laten we nu hetzelfde doen voor de productie.

  1. Stel een database in voor uw productie-app op Heroku, net zoals u deed voor de staging:heroku addons:create heroku-postgresql:hobby-dev --app wordcount-pro
  2. Push uw wijzigingen naar uw productiesite:git push pro master Merk op hoe u geen wijzigingen hoeft aan te brengen in het configuratiebestand - het stelt de database in op basis van de nieuw aangemaakte DATABASE_URL omgevingsvariabele.
  3. Pas de migraties toe:heroku run python manage.py db upgrade --app wordcount-pro

Nu hebben zowel onze staging- als productiesites hun databases ingesteld en zijn ze gemigreerd - en klaar voor gebruik!

Wanneer u een nieuwe migratie toepast op de productiedatabase, kan er sprake zijn van uitvaltijd. Als dit een probleem is, kunt u databasereplicatie instellen door een "volger" (algemeen bekend als een slave) database toe te voegen. Bekijk de officiële Heroku-documentatie voor meer informatie.



Conclusie

Dat was het voor deel 2. Als je dieper in Flask wilt graven, bekijk dan onze bijbehorende videoserie:

Gratis bonus: Klik hier om toegang te krijgen tot een gratis Flask + Python-videozelfstudie die u stap voor stap laat zien hoe u de Flask-webapp bouwt.

In deel 3 gaan we de functie voor het tellen van woorden bouwen en deze naar een takenwachtrij sturen om de langer lopende verwerking van het tellen van woorden af ​​te handelen.

Tot de volgende keer. Proost!

Dit is een samenwerkingsstuk tussen Cam Linke, mede-oprichter van Startup Edmonton, en de mensen van Real Python.



  1. Hoe installeer ik SQL Server op een Mac met VirtualBox

  2. Welk MySQL-gegevenstype moet worden gebruikt voor het opslaan van booleaanse waarden

  3. Hoe u gegevens van de laatste maand in MySQL kunt krijgen

  4. Salesforce SOQL van SQL Server