alembic migration 自动生成migration脚本以及数据初始化

本文介绍了如何使用Alembic自动化生成数据库迁移脚本,避免手动编写繁琐的创建表代码。通过sqlacodegen将现有数据库转换为model.py,并在alembic的env.py中进行配置,执行命令生成迁移脚本。数据初始化方面,提供了两种方法,包括直接执行SQL文件和使用SQLAlchemy ORM进行数据填充。

alembic migration 自动生成migration脚本

使用alembic做数据migration的时候, 创建数据表的过程往往是一种体力活, 脚本中需要这样的代码以完成数据表的创建:

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('table1',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('field1', sa.String(length=60), nullable=False),
    sa.Column('field2', sa.String(length=60), nullable=False),
    sa.Column('field3', sa.String(length=255), nullable=False),
    sa.Column('field4', sa.String(length=255), nullable=False),
    sa.Column('field5', sa.String(length=255), nullable=False),
    sa.Column('field6', sa.String(length=255), nullable=False),
    sa.Column('field7', sa.String(length=255), nullable=False),
    sa.Column('field8', sa.String(length=255), nullable=False),
    sa.Column('field9', sa.String(length=255), nullable=False),
    sa.Column('field10', sa.String(length=255), nullable=True),
    sa.Column('field11', sa.String(length=255), nullable=True),
    sa.Column('field12', sa.String(length=255), nullable=True),
    sa.Column('field13', sa.String(length=255), nullable=True),
    sa.Column('field14', sa.String(length=255), nullable=True),
    sa.Column('field15', sa.Text(), nullable=True),
    sa.Column('field16', sa.DateTime(), nullable=True),
    sa.Column('field17', sa.DateTime(), nullable=True),
    sa.Column('field18', sa.Numeric(precision=20, scale=5), nullable=True),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_index('field7_field8', 'table1', ['field7', 'field8'], unique=False)
    op.create_index(op.f('ix_table1_field3'), 'table1', ['field3'], unique=False)
    op.create_index(op.f('ix_table1_field11'), 'table1', ['field11'], unique=False)
    op.create_index(op.f('ix_table1_field10'), 'table1', ['field10'], unique=False)
    op.create_index(op.f('ix_table1_field8'), 'table1', ['field8'], unique=False)

无疑者如果是手动填写将会是非常的繁琐, 程序员是无法忍受这样的事情的.

首先alembic本身使用了sqlalchemy, 意味着实际上它能够根据sqlalchemy的model自动生成以上的migration脚本.
目录结构:

├── alembic
│ ├── env.py
│ ├── init.py
│ ├── README
│ ├── script.py.mako
│ └── versions
│   ├── 1_0_0_170310_init_db.py
│   └── init.py
├── alembic.ini
├── model.py
└── init.py

  1. 用 sqlacodegen 将存在的数据库表 转化成model.py
    首先需要安装sqlacodegen:

    pip install sqlacodegen
    然后生成model:
    
    sqlacodegen --outfile d:\\models.py mysql://test:test@localhost:3306/test  
  2. 将model.py放到根目录下, 修改env.py, 再引入处添加以下几行:

    import os
    import sys
    sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../")
    from models import Base

    然后把target_metadata = None修改为: target_metadata = Base.metadata

  3. 最后执行命令:

    alembic revision --autogenerate --rev-id REV_ID 20170313_001 -m "create tables"

    到此, 数据库表结构的migration脚本已经生成成功!

数据初始化

数据初始化有两种方式, 第一种比较简单粗暴, 就是写个sql文件, 让migration脚本去执行, 我在创建存储过程的时候选择了这种方法, 因为按照alembic的cook book里创建存储过程的方法是非常麻烦的, 不知道为何这个方法没有集成进去.

第二种方法是使用SQLAlchemy的ORM, 因为已经有了表所对应的model , 因此首先创建一个model对象, 并放到conn中去执行, 如下代码, 放到upgrade方法中:

conn = op.get_bind() 
table1 = Table1(field1='1', 
            field2='1', 
            field3='1', 
            field4='1', 
            field5='1', 
            field6='1', 
            field7='1') 
table2 = Table1(field1='2', 
            field2='2', 
            field3='2', 
            field4='2', 
            field5='2', 
            field6='2', 
            field7='2') 
conn.execute( 
    Table1.__table__.insert(), 
    [table1.to_dict(), table2.to_dict()] 
)

这样就能将数据初始化到库中了.

顺便说明下, 自动生成的model中的对象是没有to_dict方法的,需要自己添加:

class S01ChangeOrder(Base):
    __tablename__ = 's01_change_order'
    __table_args__ = (
        Index('data_source_external_key', 'data_source', 'external_key'),
    )

    id = Column(Integer, primary_key=True)
    field1 = Column(String(60), nullable=False)
    field2 = Column(String(60), nullable=False)
    field3 = Column(String(255), nullable=False, index=True)
    field4 = Column(String(255), nullable=False, index=True)
    field5 = Column(String(255), nullable=False)
    field6 = Column(String(255), nullable=False, index=True)
    field7 = Column(String(255), nullable=False)
    field8= Column(String(255), nullable=False, index=True)
    field9= Column(String(255), nullable=False)
    field10= Column(String(255))
    field11= Column(String(255))
    field12 = Column(String(255))
    field13= Column(String(255))
    field14= Column(String(255))
    field15= Column(Text)
    field16= Column(DateTime)
    field17 = Column(DateTime)
    field18= Column(Numeric(20, 5))

    def to_dict(self):
        return {c.name: getattr(self, c.name) for c in self.__table__.columns}
在执行 Flask 数据库迁移时,输出的信息如 `INFO [alembic.runtime.migration] Context impl PostgresqlImpl` 表明当前使用的迁移上下文是基于 PostgreSQL 的实现。Alembic 是 Flask-Migrate 使用的数据库迁移工具,它能够检测模型变化并生成相应的迁移脚本[^2]。 当执行迁移命令时,例如 `flask db migrate` 或 `flask db upgrade`,Alembic 会根据当前配置的数据库类型选择合适的迁移上下文。如果使用的是 PostgreSQL,则会看到类似以下的日志输出: ``` INFO [alembic.runtime.migration] Context impl PostgresqlImpl INFO [alembic.runtime.migration] Will assume transactional DDL ``` 这些信息确认了以下几点: - 当前迁移上下文为 `PostgresqlImpl`,即适用于 PostgreSQL 的迁移逻辑。 - Alembic 假设数据库支持事务性 DDL(Data Definition Language),这意味着像创建或删除表等操作可以在事务中执行,从而保证数据一致性[^1]。 此外,Flask-Migrate 提供了多种命令用于管理数据库迁移: - `flask db init`:初始化迁移环境。 - `flask db migrate`:自动生成迁移脚本以反映模型更改。 - `flask db upgrade`:应用迁移脚本数据库中,更新数据库结构[^3]。 在实际操作中,例如添加新表或修改现有列,Flask-Migrate 会检测这些变更,并通过 Alembic 创建新的迁移版本文件。执行 `flask db upgrade` 后,可以看到迁移脚本中定义的操作被应用于数据库,同时日志也会记录迁移的具体内容和结果。 ### 示例代码 以下是一个简单的 Flask 应用程序中使用 Flask-SQLAlchemy 和 Flask-Migrate 的示例: ```python from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://localhost/mydatabase' db = SQLAlchemy(app) migrate = Migrate(app, db) class User(db.Model): __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) def __repr__(self): return '<用户名:{}>'.format(self.username) ``` 在上述代码中,`Migrate` 实例负责集成 Flask-Migrate 功能,使得可以通过命令行进行数据库迁移操作。运行迁移命令后,控制台将输出相关信息,包括迁移上下文和数据库类型确认。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值