pythonsqlalchemyalembicsqlalchemy-migrate

SQLAlchemy-Migrate or Alembic deletes data when renaming model


I am using SQLAlchemy-Migrate to manage migrations for my PostgreSQL database. I changed the __tablename__ for a model, and running the migration changed the name in the database, but all the rows in the table were deleted. How can I rename a model without deleting data?

class Contract(db.Model):
    __tablename__ = 'contract'
    id = db.Column(db.Integer, primary_key=True)
    is_valid = db.Column(db.Boolean, default=IS_VALID)

I rename it from contract to contracts and get this migration:

def upgrade(migrate_engine):
    pre_meta.bind = migrate_engine
    post_meta.bind = migrate_engine
    pre_meta.tables['contract'].drop()
    post_meta.tables['contracts'].create()

It drops the old table and creates a new one. I never examined other migration scripts because they always ran without dropping the data.


Solution

  • SQLAlchemy-Migrate does not know that the table named "contract" in the database is the same as the model named "contracts" in the code. They're different names, and it only does a simple comparison. This is why you always review the generated migration scripts to make sure they do the right thing.

    From the SQLAlchemy-Migrate docs, rename a table with the rename method.

    pre_meta.tables['contract'].rename('contracts')
    

    If you're using Alembic (or Flask-Alembic, or Flask-Migrate) instead of SQLAlchemy-Migrate, the same thing happens. Use the rename_table method.

    op.rename_table('contract', 'contracts')