Search code examples
pythonsqlalchemydatabase-migrationflask-sqlalchemyalembic

How can I programmatically set the 'target_metadata' required by Alembic for use with the command API?


I'm managing database migrations with Alembic and would like to use the default files generated by alembic init without any modifications to env.py (e.g., setting target_metadata) or alembic.ini (e.g., setting sqlalchemy.url) to manage migrations of my database from scripts.

For example, I'd like to use a command based script like the following:

import os

from alembic.config import Config
from alembic import command
from myapp import db

alembic_cfg = Config(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'alembic.ini'))
alembic_cfg.set_main_option("sqlalchemy.url",
                            os.environ['DATABASE_URL'])
alembic_cfg.set_main_option("script_location",
                            os.path.join(os.path.abspath(os.path.dirname(__file__)), '.db_migrations'))
alembic_cfg.set_main_option("target_metadata", db.metadata) # This doesn't work!

command.revision(alembic_cfg, message='Test of new system', autogenerate=True)
command.upgrade(alembic_cfg, 'head')

This all works as desired, except that the indicated line fails, and I don't see a way to set the target_metadata (other than editing env.py).

How can I programmatically set the target_metadata required by Alembic in (something like) the script above, which uses Alembic's command API?


Solution

  • The long answer is that you don't set metadata there, you set it when creating the MigrationContext. Which requires that you create a Config, then a ScriptDirectory, then an EnvironmentContext first. Then you need to use these objects correctly when running revisions to set up the environment yourself.

    The short answer is that there are two extensions (that I know of) that integrate Flask-SQLAlchemy with Alembic for you. Flask-Migrate has been around for a while and provides pretty much a straight wrapper around the basic commands from Alembic.

    Flask-Alembic (written by me) (not related to an older project of the same name that is not in development) provides tighter integration with Flask and Alembic. It exposes Alembic's internals and works with the Flask dev version, but is newer and more experimental.

    They are both actively maintained. If you need to get at the internals, chose Flask-Alembic. If you just need the commands, choose Flask-Migrate.