Alembic是SQLAlchemy作者编写的Python数据库迁移工具。我打算用它实现模型类和数据库的同步更新,就先看了些资料,学习如何实现该功能。
1. 安装
我在virtualenv下直接通过pip安装,会自动安装依赖包SQLAlchemy、Mako和MarkupSafe。
1
2
3
|
pip
install
alembic
|
SAE Python环境中只需安装Mako,其他两个均为内置模块。
安装完成后就可以使用alembic命令,所有Alembic操作均由该命令实现(感觉类似git)。
2. 初始化
需要为alembic初始化,这将创建一个alembic.ini配置文件和一个alembic“档案”目录。在合适的位置运行
1
2
3
|
alembic
init
YOUR_ALEMBIC
_DIR
|
我在模块包目录下创建目录alembic_database,目录结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
myproject
/
|
--
index
.
wsgi
|
--
.
.
.
|
--
myapp
/
|
--
__init__
.
py
|
--
.
.
.
|
--
alembic
.
ini
# 配置文件
|
--
alembic_database
/
|
--
env
.
py
# 运行alembic会加载该模块
|
--
script
.
py
.
mako
# 迁移脚本生成模板
|
--
.
.
.
|
--
versions
/
# 存放迁移脚本,类似历史库
|
--
.
.
.
|
3. 创建模型类
创建一个使用SQLAlchemy定义数据库的模块,比如下面这种
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
from
myapp
import
db
from
sqlalchemy
.
schema
import
Sequence
as
Sequence
ROLE_USER
=
0
ROLE_ADMIN
=
1
# use?
class
User
(
db
.
Model
)
:
id
=
db
.
Column
(
db
.
BigInteger
(
64
)
,
Sequence
(
'id_seq'
)
,
primary_key
=
True
)
uid
=
db
.
Column
(
db
.
BigInteger
(
64
)
,
unique
=
True
)
info
=
db
.
Column
(
db
.
Text
(
)
)
update_time
=
db
.
Column
(
db
.
DateTime
(
)
)
create_time
=
db
.
Column
(
db
.
DateTime
(
)
)
def
__init__
(
self
,
uid
,
info
)
:
self
.
uid
=
uid
self
.
info
=
info
def
__repr__
(
self
)
:
return
''
%
self
.
uid
|
上面例子中定义一个表user。
4. 修改配置文件
在alembic.ini中设置数据库连接
1
2
3
|
sqlalchemy
.
url
=
driver
:
/
/
user
:
pass
@
localhost
/
dbname
|
为了使用模型类更新数据库,需要在env.py中设置,将target_metadata赋值成数据库的元数据(metadata)。原有配置如下
1
2
3
|
target_metadata
=
None
|
可修改为
1
2
3
4
5
6
7
8
9
|
import
os
import
sys
root
=
os.path
.
dirname
(
__file__
)
+
'/../../'
# 定位到project根目录
print
root
sys
.
path
.
append
(
root
)
from
myapp
import
db
target_metadata
=
db
.
metadata
|
自此,alembic将可以获取模型模块中定义的信息。
5. 创建版本
用 alembic revision -m+注释 创建数据库版本。由于我提供了模型类,所以可以用–autogenerate参数自动生成迁移脚本。运行
1
2
3
|
alembic
revision
--
autogenerate
-
m
"create user table"
|
显示
1
2
3
4
|
INFO
[
alembic
.
migration
]
Context
impl
MySQLImpl
.
INFO
[
alembic
.
migration
]
Will
assume
non
-
transactional
DDL
.
INFO
[
alembic
.
autogenerate
]
Detected
added
table
'user'
Generating
(省略
)
myapp
\
alembic_database
\
versions
\
1c02a7117955_create_user_table.py...done
|
生成的数据库迁移脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
"""create user table
Revision ID: 1c02a7117955
Revises: None
Create Date: 2013-08-30 01:03:51.703000
"""
# revision identifiers, used by Alembic.
revision
=
'1c02a7117955'
down_revision
=
None
from
alembic
import
op
import
sqlalchemy
as
sa
def
upgrade
(
)
:
### commands auto generated by Alembic - please adjust! ###
op
.
create_table
(
'user'
,
sa
.
Column
(
'id'
,
sa
.
BigInteger
(
)
,
nullable
=
False
)
,
sa
.
Column
(
'uid'
,
sa
.
BigInteger
(
)
,
nullable
=
True
)
,
sa
.
Column
(
'info'
,
sa
.
Text
(
)
,
nullable
=
True
)
,
sa
.
Column
(
'update_time'
,
sa
.
DateTime
(
)
,
nullable
=
True
)
,
sa
.
Column
(
'create_time'
,
sa
.
DateTime
(
)
,
nullable
=
True
)
,
sa
.
PrimaryKeyConstraint
(
'id'
)
,
sa
.
UniqueConstraint
(
'uid'
)
)
### end Alembic commands ###
def
downgrade
(
)
:
### commands auto generated by Alembic - please adjust! ###
op
.
drop_table
(
'user'
)
### end Alembic commands ###
|
两个函数用于数据库的升级和降级。
6. 更新数据库
升级数据库使用alembic upgrade,降级使用alembic downgrade。更新到最新版
1
2
3
4
5
6
|
$
alembic
upgrade
head
INFO
[
alembic
.migration
]
Context
impl
MySQLImpl
.
INFO
[
alembic
.migration
]
Will
assume
non
-
transactional
DDL
.
INFO
[
alembic
.migration
]
Running
upgrade
None
->
1c02a7117955
,
create
user
table
|
查看数据库,发现已经创建user表。还有一个表叫做alembic_version,只有一个字段和一个值version_num,记录当前的数据库版本。
我在SAE Python本地开发环境中使用遇到问题,代码中使用pylibmc库,但SAE Python本地开发环境用sae.memcache模块代替pylibmc模块,dev_server.py中有下面的代码
1
2
3
4
|
import
sae
.
memcache
sys
.
modules
[
'pylibmc'
]
=
sae
.
memcache
|
直接使用pylibmc在dev_server.py下没有问题,但运行alembic程序时则会提示找不到该模块。为了解决这个问题,我判断是本地开发环境还是线上开发环境,分别载入不同的库。
1
2
3
4
5
6
|
if
app
.
config
[
'ONLINE'
]
:
import
pylibmc
else
:
import
sae
.
memcache
as
pylibmc
|
参考
alembic官方教程 http://alembic.readthedocs.org/en/latest/tutorial.html
《Alembic 简明教程》http://huangx.in/18/alembic-simple-tutorial
《使用alembic》 http://my.oschina.net/banxi/blog/126695
sqlalchemy-migrate 另一款适用于SQLAlchemy的数据库迁移工具
问题
SAE线上环境使用的SQLAlchemy版本为0.7.10,使用Alembic时出现如下错误:
1
|
AttributeError
:
'MetaData'
object
has
no
attribute
'schema'
|
似乎对MetaData的支持不够,版本号过低。升级成0.8.5,就可以正常使用。
重新生成脚本
我使用Alembic时,已经使用SQLAlchemy建立初始模型的数据表,不是从零开始,所以无法使用Alembic完整迁移数据库。所以,我使用Alembic重新生成数据库迁移脚本。
Alembic在数据库中仅保存当前版本号,其余信息均从文件读取。删除历史记录,只需要将数据库表删除,并删除versions下的所有文件。而alembic.ini和env.py中的设置无需更改,可以再次使用。
[转载:http://windrocblog.sinaapp.com/?p=940]