alembic是配合SQLAlchemy的一个工具,可以方便的upgrade或downgrade数据库,而不用每次修改都进行reset操作导致数据丢失。
安装和初始化
pip install alembic
安装之后在project的目录下面执行初始化命令:
alembic init APP/NAME
这里APP是我Flask的APP名称,NAME是存放alembic初始化文件的文件夹名称,我这里用的是migrations。
初始化后,进入migrations文件夹,会有versions文件夹,每次生成的revision file会在这儿,env.py环境文件,根据项目设置,以及script.py.mako产生revision file的模板文件,如果需要可以自定义,这里我是将常用的sqlalchemy及时间相关的包导入放在了这里,不用每次都去添加。
在project文件夹下还有一个alembic.ini的文件,也是初始化生成的。
首次使用
docker-compose up # 启动image
假设现在我们要添加一个foo table,执行下面的命令创建一个revision file:
docker-compose exec --user "$(id -d):$(id -g)" website alembic revision -m "create foo table"
其实除开docker的命令,这个和git的使用是很像的,–user “
生成的文件在versions文件夹下,文件名为HASH_注释的信息.py,upgrade和downgrade本应为pass,这里我已经手动修改了:
import sqlalchemy as sa
from alembic import op
from lib.util_datetime import tzware_datetime
from lib.util_sqlalchemy import AwareDateTime
"""
create foo table
Revision ID: 934098c9f899
Revises:
Create Date: 2017-08-16 01:34:43.895131
"""
# Revision identifiers, used by Alembic.
revision = '934098c9f899'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table('foos',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('created_on', AwareDateTime(),
default=tzware_datetime),
sa.Column('updated_on', AwareDateTime(),
default=tzware_datetime,
onupdate=tzware_datetime),
sa.Column('bar', sa.String(128), index=True))
def downgrade():
op.drop_table('foos')
手动修改了upgrade和downgrade方法后,就可以去terminal中运行了:
docker-compose exec website alembic upgrade head
这里head始终表示revision的最新文件,即使你多次降级后,执行upgrade head仍然是执行的最新的revision file。
升级成功后,会提示已经指向了这次升级的revision的hash。同理,降级:
docker-compose exec website alembic downgrade -1
降级一次,升级也能用+1,这里也可以用其他数字。
写到这里,大家可能觉得不好用,因为这还没有结合SQLAlchemy来使用。
与SQLAlchemy一起用
加减个新表不是使用alembic的真正价值所在,这次我们需要在users的表中增加一列foobar。
首先,我们找到users models.py,在User下直接添加一列foobar,这时再升级就需要使用–autogenerate这个flag了,他能帮我们自动的生成相应的revision file,而不是生成空白的自己去填写,我们需要做的就是检查是否正确,做修改后执行升级操作:
docker-compose exec --user "$(id -u):$(id -g)" website alembic revision --autogenerate -m "add foobar column to users"
这里会生成一个新的revision file,但是你会发现这里有对foo table的操作,比如会在升级的时候drop foo table,因为自动生成是根据ORM的关系来构建的,而foo是我们通过修改revision file生成的,不存在于model中,所以,这里如果要保留foo就应该将其中对foo的操作去掉,去掉后结果如下:
import sqlalchemy as sa
from alembic import op
from lib.util_datetime import tzware_datetime
from lib.util_sqlalchemy import AwareDateTime
from sqlalchemy.dialects import postgresql
"""
add foobar column to users
Revision ID: d7676576f4ef
Revises: 73428a75ef16
Create Date: 2017-08-16 15:16:10.539365
"""
# Revision identifiers, used by Alembic.
revision = 'd7676576f4ef'
down_revision = '73428a75ef16'
branch_labels = None
depends_on = None
def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('users', sa.Column('foobar', sa.String(length=128), nullable=True))
op.create_index(op.f('ix_users_foobar'), 'users', ['foobar'], unique=False)
### end Alembic commands ###
def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_users_foobar'), table_name='users')
op.drop_column('users', 'foobar')
### end Alembic commands ###
这时我们再去执行一次升级操作就能完成对users这个表添加foobar列的操作。
补充命令行
docker-compose exec website alembic current # 查询当前所在的revision
docker-compose exec website alembic history --verbose # revision的详细历史记录
其他不清楚的都能用 –help这个flag查询。