使用alembic管理数据库版本

介绍

一个项目除了代码需要使用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啥的。

# alembic 

右下角对话与我联系。


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×