Home » Beitrag verschlagwortet mit 'DB Migration'
Schlagwort-Archive: DB Migration
Flask DB Migrations
Links
- Flask-Migrate
- Alembic (used by Flask-Migrate under the hood)
Flask-Migrate ist die Library um DB-Modell-Änderungen, die mit SQLAlchemy ausgedrückt sind zu kontrollieren. Es benutzt dazu die Library Alembic.
Schritte
Aufsetzen Flask Migrate Tool
Steps:
pip3 install Flask-Migrate
Projekt bezüglich Migrations-Handling aufsetzen
flask db init
Das setzt verschiedene Migrations-Script-Folders und Tools im SW-Projekt bereit.
Output:
C:\tmp\Python_Workspace1\task-app>flask db init
Creating directory C:\tmp\Python_Workspace1\task-app\migrations ... done
Creating directory C:\tmp\Python_Workspace1\task-app\migrations\versions ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\alembic.ini ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\env.py ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\README ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\script.py.mako ... done
Please edit configuration/connection/logging settings in 'C:\\tmp\\Python_Workspace1\\task-app\\migrations\\alembic.ini' before proceeding.
Funktioniert das Kommando nicht, weil die DB noch nicht gestartet ist, dann etwa folgendes absetzen:
pg_ctl -D "C:\Program Files\PostgreSQL\13\data" start
DB-Migrationen durchführen
flask db migrate
Erkennt die Anforderungen an das DB-Modell aus den Python-Scripts (aus den SQLAlchemy Model-Objekt-Definitionen) heraus und erstellt eine Migration (DDL Statements um das erforderliche DB-Model zu erstellen).
Ich gehe schwer davon aus, das dazu FLASK_APP auf das Python-Script mit den Entitätsdefinitionen zeigen muss.
Bsp. einer SQLAlchemy Model-Objekt-Definition im *.py:
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
Falls das erzeugte Script das ganze DB-Modell von Grund auf neu erzeugen soll, dann darf die DB diese Entitäten nicht schon enthalten. Das kann man zum Bsp. erreichen durch:
dropdb --username=postgres todoDB
createdb --username=postgres todoDB
!Stelle sicher, dass das Pyton-Script, nicht schon selbst die DB-Objekte erstellt (Z.B. Kommando db.create_all() darf nicht auch schon im Python-Code enthalten sein).
Durchführung:
C:\tmp\Python_Workspace1\task-app>flask db migrate
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'todos'
Generating C:\tmp\Python_Workspace1\task-app\migrations\versions\70ee48c313e4_.py ... done
C:\tmp\Python_Workspace1\task-app>
Ein Migrations-File wurde erstellt: task-app/migrations/versions/70ee48c313e4_.py
:
"""empty message
Revision ID: 70ee48c313e4
Revises:
Create Date: 2021-07-22 15:15:43.733091
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '70ee48c313e4'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('todos',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('description', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('todos')
# ### end Alembic commands ###
Migration auf die DB spielen:
C:\tmp\Python_Workspace1\task-app>flask db upgrade
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 70ee48c313e4, empty message
Migration rückgängig machen wäre:
flask db downgrade
Prüfung, ob DB-Migrationen auf DB angekommen sind:
C:\tmp\Python_Workspace1\task-app>psql --username=postgres todoDB
Passwort für Benutzer postgres:
todoDB=# \dt
Liste der Relationen
Schema | Name | Typ | Eigent³mer
--------+-----------------+---------+------------
public | alembic_version | Tabelle | postgres
public | todos | Tabelle | postgres
(2 Zeilen)
todoDB=#
Beachte die alembic_version
Tabelle! Beinhaltet die Migrationsinfo. Prinzipiell nicht durch den Programmierer zu verändern.
Wenn nun Änderungen am DB-Modell innerhalb des Python-Scripts gemacht werden (z.B. wird hier das boolean Feld ‚completed‘ neu hinzu gefügt),
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
completed = db.Column(db.Boolean(), nullable=False, default=False)
…, dann wird mit flask db migrate
ein neues Update-Script erstellt und mit flask db update
dieser Update auf die DB gespielt.
Beheben der Problematik des Hinzufügens von NOT-NULL Feldern:
Das Migrations-Script folgendermassen anpassen:
from alembic import op
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('todos', sa.Column('completed', sa.Boolean(), nullable=True))
op.execute('update todos set completed=False where completed is null')
op.alter_column('todos', 'completed', nullable=False)
# ### end Alembic commands ###