Title: Basic Alembic Migrations with Flask Date: 2013-05-10 12:06 Author: Michael Category: Python Tags: alembic, sqlalchemy, flask Slug: basic-alembic-migrations-with-flask Status: published
This post will cover the minimal set-up to get basic (auto-generating) Alembic migrations working within a Flask application. The pre-requisites are; Flask, SQLAlchemy, Flask-SQLAlchemy and Alembic in case that wasn’t obvious.
My current project is being built with Flask utilizing SQLalchemy as an abstraction to my data persistence layer AKA ORM. I am also using the Flask-SQLALchemy extension to make life even easier. In the fantastic Flask Mega Tutorial Miguel Grinburg uses sqlalchemy-migrate to manage the migrations of his database. I found the code to be a bit heavy-handed and fragile, not to mention that sqlalchemy-migrate is incompatible with versions of SQLAlchemy greater than 0.8, nor has it seen an update in sometime. The constant churn of packages and frameworks is a
riskfeature of Open Source Software. One has to be comfortable with this situation and I am!
That said, to the database migration rescue comes Alembic. This package is written by Mike Mayer who happens to be the father of SQLAlchemy itself. I can’t think of another person who would be more qualified to write such a tool than he. We are a truly lucky lot in this case!
On with it now!
This first thing you need to do is create the migration environment. I suggest creating a virtualenv for your project before you start.
Once you have activated your virutalenv:
:::bash $ cd yourproject $ pip install alembic $ alembic init alembic
This command creates an Alembic directory and alembic.ini file in your project directory. Running
alembic init alembic
creates a generic configuration. Run it as described above unless you have a multi-database or a pylons project. The docs
for this are here.
Just like SQLAlchemy, I believe Alembic is customizable to its very core, but I am no expert. For my simple mission to get Alembic running, I chose to leave this file as is. I will revisit this aspect if conditions warrant in a future post.
This is where I made some modifications to the generated file to get it working with Flask.
:::python from __future__ import with_statement import os, sys sys.path.append(os.getcwd()) from alembic import context from sqlalchemy import engine_from_config, pool from logging.config import fileConfig from <application> import app from <application>.models import db # This is the 'Generic' alembic modified with some settings # specific to this app # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config # Overwrite the sqlalchemy.url in the alembic.ini file. config.set_main_option('sqlalchemy.url', app.config['SQLALCHEMY_DATABASE_URI']) # Interpret the config file for Python logging. # This line sets up loggers basically. fileConfig(config.config_file_name) # add your model's MetaData object here # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata target_metadata = db.metadata
- Import os and sys to modify the path. I am not sure if this is a bug in Alembic, but I could not get Alembic to find my modules without appending the current working directory to my path.
- Import your app and db. Note: this is application specific as Flask will let you set these up in a few different places.
- Override the sqlalchemy.url in Alembic.ini file with a pointer to your applications database config
- Use db.metadata to provide automatic migration generation support.
:::bash $ alembic revision --autogenerate -m "<insert message here>"
You can inspect and modify the migration created by looking in the
Docs for this are here
:::bash $ alembic upgrade head
Docs for this are here.
… and we are good to go! Basic Alembic migrations should be running with most Flask apps. Flask is great framework for building python web apps. I plan on using it extensively for the next few projects floating around in my head. There will be a lot more on that front in due time. I will be sure to post more on my adventures with Flask, SQLAlchemy, Alembic and others as time permits…