Database Scenarios¶
You can use Flask-Alembic with Flask-SQLAlchemy, Flask-SQLAlchemy-Lite, or plain SQLAlchemy. Alembic’s single and multiple database templates are supported.
Flask-SQLAlchemy¶
The default engine (db.engine) and metadata (db.metadata) will automatically
be used. If multiple binds are configured, they (db.engines) will be used if
multiple metadatas are configured in Flask-Alembic. Additional metadata
(db.metadatas) will not be used automatically however, as it’s not possible to
know which are external and should not be migrated.
Flask-SQLAlchemy-Lite¶
The default engine (db.engine) will automatically be used. Since
Flask-SQLAlchemy-Lite does not manage the models, tables, or metadata itself,
the metadata you define must be passed to Alembic.
from flask_alembic import Alembic
from sqlalchemy.orm import DeclarativeBase
class Model(DeclarativeBase):
pass
alembic = Alembic(metadatas=Model.metadata)
Plain SQLAlchemy¶
If you are not using either extension, but defining SQLAlchemy engines and
models/metadata manually, you can pass them to Alembic. You can also do this
when using either extension to control exactly what is used for migrations.
from flask_alembic import Alembic
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase
engine = create_engine("sqlite:///default.sqlite")
class Model(DeclarativeBase):
pass
alembic = Alembic(metadatas=Model.metadata, engines=engine)
Multiple Databases¶
If you need to manage migrations across multiple databases, you can specify
multiple metadata and engines to run migrations on. Flask-Alembic will use
Alembic’s suggested multidb template for generating and running migrations.
The metadatas argument can be a dict mapping string names to a single
metadata or list of metadatas. When using Flask-SQLAlchemy(-Lite), db.engines
is automatically used, so the keys there should match up with the keys in
metadatas. Otherwise, the engines argument can be a dict mapping the same
string names to engines.
from flask import Flask
from flask_alembic import Alembic
from flask_sqlalchemy_lite import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase
class DefaultBase(DeclarativeBase):
pass
class AuthBase(DeclarativeBase):
pass
db = SQLAlchemy()
alembic = Alembic(
metadatas={
"default": DefaultBase.metadata,
"auth": AuthBase.metadata,
},
)
app = Flask(__name__)
app.config["SQLALCHEMY_ENGINES"] = {
"default": "sqlite:///default.sqlite",
"auth": "postgresql:///app-auth",
}
db.init_app(app)
alembic.init_app(app)
When alembic.init_app is called, it creates the migrations directory and
script template if it does not exist. It will choose the generic (single
database) template if only one name is configured, or the multidb template if
more are configured. Due to the way Alembic works, the two templates are not
compatible. If you switch to single or multiple databases later after generating
migrations, you’ll need to replace the script.py.mako file and modify the
existing migrations. A good strategy in that scenario may be to delete existing
migrations and start from scratch.
Multiple Metadatas¶
It’s possible to split your models/tables for a database across multiple
metadatas. In that case, you can pass a list of metadatas instead of a single
metadata. If you’re only managing a single database, you can pass the list
directly to metadatas, otherwise any value in the dict can be a list.
from flask_alembic import Alembic
from sqlalchemy.orm import DeclarativeBase
class DefaultBase(DeclarativeBase):
pass
class AuthBase(DeclarativeBase):
pass
alembic = Alembic(metadatas=[DefaultBase.metadata, AuthBase.metadata])