Using Alembic Migrations with multiple projects

1.4k views Asked by At

I have two Flask applications using Flask-Migrate and Alembic.

There are three tables, with one table that is shared between the two Flask applications, and is represented by shared_models.py

I am running into the difficulty that the shared table gets stamped with one of the projects alembic_version, and then the other project complains about it, despite the shared_models.py file being identical.

What is a good strategy for handling this kind of environment?

2

There are 2 answers

0
Miguel Grinberg On

One option would be to use two separate databases for your two applications. You will have to decide which of the two apps owns the table that is shared. Each application tracks migrations on its own database, and the application that does not own the shared table accesses this table from the other app's database via the binds feature of Flask-SQLAlchemy.

This is not the only option. Another that comes to mind, is to keep using a single database, but configure Alembic on one of the two apps to ignore this shared table. This would have to be done manually on the env.py file, Flask-Migrate does not have direct support to generate the code to ignore tables.

0
pxeba On

A better approach is to include the --directory option in the flask db migrate command. This way you can link the projects passing the path of the migrations folder in the reference project


To make it easier to understand I made an example in 3 steps:


  1. In the first project, you can define the connection between the tables using a "bind" type relationship, which allows a table from a database to connect to another table from a different database. To do this, define the Coupon class again, this time using the bind_key() function to specify the connection to the second database.
#project 1 
class Cupom(db.Model):
    __tablename__ = 'cupom'
    __bind_key__ = 'db2'

    id = db.Column(db.Integer, primary_key=True)
    name= db.Column(db.String(50), nullable=False)
#project 2
class Cupom(db.Model):
    __tablename__ = 'cupom'

    id = db.Column(db.Integer, primary_key=True)
    name= db.Column(db.String(50), nullable=False)

  1. Configure the database connection in each project. Each project must have its own database and its own connection credentials. You can configure this information in a configuration file or in environment variables.
# Database setup for the first project
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://user:password@localhost/db1'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_BINDS'] = {
    'db2': 'mysql://user:password@localhost/db2'
}
db.init_app(app)

# Database setup for the second project
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://user:password@localhost/db2'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)

  1. Perform database migrations on each project using Flask-Migrate. For the first project, specify the connection to the second database using the --directory option in the flask db migrate command.
# Running the migrations on the first project
export FLASK_APP=projeto1
flask db init
flask db migrate --directory=../projeto2/migrations
flask db upgrade

# Running the migrations on the second project
export FLASK_APP=projeto2
flask db init
flask db migrate
flask db upgrade

Something that might be useful. To separate a migration for your project's models and another for shared models you need to create a directory, inside one of the 2 projects or inside a git submodule/subtree they use and make a new flask db init, flask_migrate and upgrade inside him