Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alembic autogenerates empty Flask-SQLAlchemy migrations

I'm using Alembic to handle migrations for Flask. alembic revision --autogenerate should, in theory, autogenerate a migration based on changes in my database. However, Alembic is simply generating a blank migration with the above command.

There's a question very similar to this one, where the issue was that the proper models weren't being imported. However, I have imported the models from my Flask app, as shown in env.py:

...
# import settings from Flask
alembic_config = config.get_section(config.config_ini_section)
from start import app
from models import User, Item, Recipient # models are imported here from models.py
alembic_config['sqlalchemy.url'] = app.config['SQLALCHEMY_DATABASE_URI']

engine = engine_from_config(
            alembic_config, # config.get_section(config.config_ini_section)
            prefix='sqlalchemy.',
            poolclass=pool.NullPool)
...

As well as imported db metadata in env.py ('start' is the name of my Flask app's main file):

...
from start import db
target_metadata = db.metadata
...

Running alembic revision --autogenerate -m "initial_rev" then generates an empty migration, although my Flask app would beg to differ:

"""initial_rev

Revision ID: 45296fd29540
Revises: None
Create Date: 2013-06-19 17:32:38.392268

"""

# revision identifiers, used by Alembic.
revision = '45296fd29540'
down_revision = None

from alembic import op
import sqlalchemy as sa


def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    pass
    ### end Alembic commands ###


def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    pass
    ### end Alembic commands ###

Edit

Here is a gist that shows the file structure for my app, as well as some additional code. It seems the issue is that Alembic does not like having the db imported from database.py without being initialized first in __init__.py. However, this is not possible when blueprints are used (because of cyclical imports), explained in this SO answer: https://stackoverflow.com/a/9695045/353878.

So the question is, how can Alembic be used when Flask blueprints are used as well?

Edit #2

I even tried printing db.metadata.sorted_tables, to make sure the database metadata was being imported correctly. Sure enough, the whole database schema was piped to the terminal. So why is Alembic generating blank upgrade/downgrade functions?

Edit #3

I've concluded that the issue has something to do with the differences of db.init_app(app) and db = SQLAlchemy(app), but I'm not quite sure what is causing the issue. To test this theory, I replaced from database import db in env.py to be db = SQLAlchemy(app). Probably a bad idea, but I wanted to see what would happen for debugging purposes.

Alembic autogenerated and filled the upgrade() and downgrade() methods- except they were reversed! upgrade() dropped all three of my tables, while downgrade() created them with all the proper columns and metadata. I have no idea why this is, but I hope it is helpful to people trying to figure out this problem.

like image 214
element119 Avatar asked Jun 19 '13 21:06

element119


People also ask

What is alembic Autogenerate?

Alembic can view the status of the database and compare against the table metadata in the application, generating the “obvious” migrations based on a comparison. This is achieved using the --autogenerate option to the alembic revision command, which places so-called candidate migrations into our new migrations file.

How do you change heads in alembic?

Show activity on this post. Delete (or move to another folder) the specific migration file (in migrations/versions folder). The head will automatically revert to the most recent remaining migration. Using stamp will set the db version value to the specified revision; not alter the head revision number.

What is Sqlalchemy migration?

The sqlalchemy migrations are one of the features, and it migrates to provide a way of dealing with the database schema and its changes in the sqlalchemy projects; it migrates the data with the help of some tools like alembic is one of the data migration tools that offer the Alter statement to the specific database to ...


1 Answers

Here is how I use Alembic with Flask and blueprints.

https://github.com/davidism/basic_flask

I use the application factory pattern and call db.init_app within that. After db = SQLAlchemy() I import all models that will subclass db.Model so that db.metadata is aware of them; note this is not done in the create_app factory, but just inline during module init.

When running alembic, the project folder is not included in sys.path so I set that up. Then I create an app from the factory and set sqlalchemy.url from its configuration. Also, I import db and set target_metadata = db.metadata.

This setup works for me all the time, no matter the project structure. I included a very basic set of user models and a very dumb view in a subpackage with a blueprint. Just make sure to load the relavent models in load_models, import the views after defining the blueprint, and import the blueprints in init_views.

like image 156
davidism Avatar answered Oct 24 '22 03:10

davidism