介绍
一个项目除了代码需要使用git保存,进行可追溯的版本管理,通常还需要管理数据库,这个数据库可能会随着项目的演进发生变化(增加字段,删除字段等),甚至需要可以回滚到过去的某个状态。
Alembic 是 Sqlalchemy 的作者实现的一个数据库版本化管理工具,它可以对基于Sqlalchemy的Model与数据库之间的历史关系进行版本化的维护。
安装
pip install alembic
使用
拿我自己的一个瞎折腾来举例子,一直在折腾无服务器云函数,然后想爬下小说(虽然已经很长很长的时间没有看过了)数据放在上面,现在还有个云函数每天在爬某族5
初始化一个项目
alembic init your_project_name
创建映射orm,
- 在项目alembic.ini添加数据库连接信息
sqlalchemy.url = mysqldriver://usernmae:password@ip:port/database_name
- 在项目alembic.ini 同级创建一个models.py
# -*- coding: utf-8 -*-
from sqlalchemy import Column, ForeignKey, Index, UnicodeText, Unicode
from sqlalchemy.dialects.mysql import INTEGER
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
metadata = Base.metadata
class NovelAuthor(Base):
__tablename__ = 'novel_author'
id = Column(INTEGER(11), primary_key=True)
name = Column(Unicode(32), nullable=False)
description = Column(UnicodeText, nullable=False)
class NovelBook(Base):
__tablename__ = 'novel_book'
id = Column(INTEGER(11), primary_key=True)
name = Column(Unicode(32), nullable=False)
description = Column(UnicodeText, nullable=False)
author_id = Column(ForeignKey('novel_author.id', name='book_author_id'))
author = relationship('NovelAuthor')
class NovelChapter(Base):
__tablename__ = 'novel_chapter'
__table_args__ = (
Index('chapter_book_unique', 'chapter', 'book_id', unique=True),
)
id = Column(INTEGER(11), primary_key=True)
title = Column(Unicode(32), nullable=False)
content = Column(UnicodeText, nullable=False)
book_id = Column(ForeignKey('novel_book.id', name='book_chapter_id'))
book = relationship('NovelBook')
chapter = Column(INTEGER(11))
- 替换env.py 文件里的 target_metadata
import os, sys
sys.path.append(os.getcwd())
from models import Base
target_metadata = Base.metadata
# target_metadata = None
生成版本文件(自动/手动)
alembic revision --autogenerate -m "版本备注信息,类似git commit -m" # 在models里添加或者修改,自动生成版本文件,不过最好在生成的版本文件里检查一下是否正确
alembic revision -m "版本备注信息,类似git commit -m" # 手动生成,生成完之后需要自己在版本文件里对应的upgrade 和 downgrade 添加执行的代码
执行完命令之后,会在versions 文件夹下生成对应的一个版本文件
revision = 'f2fe76ef1cb2' # 这个是版本号,升级或者降级都需要用到
down_revision = None # 上一个版本号,因为这个是初始第一个版本,所以为空,
branch_labels = None
depends_on = None
def upgrade():
......
def downgrade():
......
- 升级/降级
alembic upgrade head # 直接升级到最新版本
alembic upgrade version_number # 升级到指定的版本
alembic downgrade version_number # 降级到指定的版本
- 在数据库里面查看
数据库里会有一张alembic_version 表用来记录当前数据库的版本。
稍微高级一点的
- 自定义版本模板文件
有时候项目可能会需要同时支持sqlite或者mysql,而这两个数据库的语法不太一样,我目前的做法是根据连接信息的driver来判断的
from alembic import op, context
def is_sqlite():
config = context.config
return config.get_main_option('sqlalchemy.url').startswith('sqlite')
通过上面这个函数返回当前是mysql 还是 sqlite。
生成的版本文件的格式是根据模板(script.py.mako)来的,所以只需要在模板文件里添加上刚才的那段代码,以后生成的版本文件就都会带上这段代码了。
- alembic.command.stamp
有时候我们手动改完数据库或者各种乱七八糟的原因,我们需要把数据库的版本信息和当前项目的对应起来,可以使用alembic.command.stamp这个命令来执行,或者直接在数据库里的alembic_version 表里手动改。
from alembic import command
alembic_cfg = Config(os.path.join(os.path.dirname(__file__), 'alembic.ini'))
command.stamp(alembic_cfg, "你想要的版本")
End
还有很多很多用法,merge啊,create_all啥的。