Is invoking SQLAlchemy's declarative_base()—bypassing Flask-SQLAlchemy's models—a sanctioned workflow? #534
-
In Apache Superset we use Flask-Migrate (in conjunction with Flask-SQLAlchemy) to handle our Alembic migrations. For a specific migration which augments the contents of the data (as opposed to the schema) we tend to redefine our models (with only the subset of impacted columns) via SQLAlchemy (as opposed to Flask-SQLAlchemy) and use Alembic for interfacing with the bind/connection: from alembic import op
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from superset import db
Base = declarative_base()
class Dashboard(Base):
__tablename__ = "dashboards"
id = Column(Integer, primary_key=True)
title = Column(String(length=256))
def upgrade():
session = db.Session(bind=op.get_bind())
for dashboard in session.query(Dashboard).all():
dashboard.title = dashboard.title.upper()
session.commit() To the best of my knowledge, the historic reason for using SQLALchemy's
I'm currently working on a refactor (apache/superset#26172) to try to ensure Flask-Migrate leverages the Flask-SQLAlchemy session ( from superset import db
class Dashboard(db.Model):
__tablename__ = "dashboards"
__table_args__ = {"extend_existing": True}
id = db.Column(Integer, primary_key=True)
title = db.Column(db.String(length=256))
def upgrade():
for dashboard in db.session.query(Dashboard).all():
dashboard.title = dashboard.title.upper()
db.session.commit() The
however this merely extends (as opposed to replacing) the I've struggled to find how to resolve this—either via numerous Google searches or ChatGPT—and was wondering what preferred Flask-Migrate/Flask-SQLAlchemy approach is? Is the |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
I'm not sure who decides what is sanctioned and what is not. I don't think it's me. ;-) Now if you are asking me if I like this solution, then no, I do not like it. You are working with two declarative bases, the one from Flask-SQLAlchemy and one more that you define yourself. The part that I do agree with you with is that sometimes it is convenient to have access to models in migration scripts, and in that case the only way to make a migration script work well is to include a copy of the model(s) in question in the migration script itself. Looks like you already figured out that the important rule is to never use your application's models in your migrations scripts. I think your issue is that when you do So I'd say these are the recommendations:
Hope this helps! |
Beta Was this translation helpful? Give feedback.
Yes, I see now that what I suggested is not really possible. The project in which I've done this was implemented with SQLAlchemy and Alembic directly, not with Flask and Flask-Migrate. That gives you more control over what gets imported. The
flask
command imports your Flask app, and to create this object pretty much everything must be imported.Unfortunately I do not have any great ideas. I think every solution is going to be hacky. I think the only reasonable option is to avoid using models in migration scripts, which is actually what the vast majority of people do, what 99.9% of projects I have been involved with do, and what the automatic migration generator does as well.