Alembic 簡明教程
本文記錄了Alembic的主要使用過程。
數據庫版本化
通常我們會將我們的代碼放入到某個VCS(版本控制系統)中,進行可追溯的版本管理。一個項目除了代碼,通常還會有一個數據庫,這個數據庫可能會隨着項目的演進發生變化,甚至需要可以回滾到過去的某個狀態,於是一些工具將數據庫的版本化也納入了管理。
Alembic 是 Sqlalchemy 的作者實現的一個數據庫版本化管理工具,它可以對基於Sqlalchemy的Model與數據庫之間的歷史關係進行版本化的維護。
Alembic
你可以通過 pip install alembic 直接安裝,它需要三個依賴包,PIP會自動處理。
SQLAlchemy 同作者的ORM工具
Mako 同作者的模版工具
MarkupSafe 轉換Markup到HTML的組件
初始化
在你的項目根目錄運行
alembic init YOUR_ALEMBIC_DIR
隨後你的項目目錄應該會新增一個alembic.ini文件以及一個YOUR_ALEMBIC_DIR目錄,最好指定一個符合自己項目風格的命名。
接下來的操作都是圍繞這個目錄。
yourproject/
alembic.ini
YOUR_ALEMBIC_DIR/
env.py
README
script.py.mako
versions/
3512b954651e_add_account.py
2b1ae634e5cd_add_order_id.py
3adcc9a56557_rename_username_field.py
alembic.ini 提供了一些基本的配置
env.py 每次執行Alembic都會加載這個模塊,主要提供項目Sqlalchemy Model 的連接
script.py.mako 遷移腳本生成模版
versions 存放生成的遷移腳本目錄
除了基本的Alembic項目之外,你還可以指定幾個特殊的項目模版。
$ alembic list_templates
Available templates:
generic - Generic single-database configuration.
multidb - Rudimentary multi-database configuration.
pylons - Configuration that reads from a Pylons project environment.
Templates are used via the 'init' command, e.g.:
alembic init --template pylons ./scripts
你需要編輯alembic.ini文件去指定Alembic的數據庫連接。
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of auto generate
# revision_environment = false
sqlalchemy.url = driver://user:pass@localhost/dbname
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
版本
首先創建一個基本數據庫版本,你當然可以從已有的數據庫出發。
$ alembic revision -m "create account table"
Generating /path/to/yourproject/YOUR_ALEMBIC_DIR/versions/1975ea83b712_create_accoun
t_table.py...done
生成的版本文件類似於:
"""create account table
Revision ID: 1975ea83b712
Revises: None
Create Date: 2011-11-08 11:40:27.089406
"""
# revision identifiers, used by Alembic.
revision = '1975ea83b712'
down_revision = None
from alembic import op
import sqlalchemy as sa
def upgrade():
pass
def downgrade():
pass
其中 revision = '1975ea83b712'和down_revision = None指定了這個reversion的當前版本號,以及父版本號,就是通過這個進行追溯。
然後我們修改upgrade和downgrade進行實際的升降級操作。通過易用的API,我們只需要對op和sa對象進行操作即可。
def upgrade():
op.create_table(
'account',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('name', sa.String(50), nullable=False),
sa.Column('description', sa.Unicode(200)),
)
def downgrade():
op.drop_table('account')
具體op所支持的操作請看操作API引用。
升級,降級
然後我們更新好最新的版本。
$ alembic upgrade head
INFO [alembic.context] Context class PostgresqlContext.
INFO [alembic.context] Will assume transactional DDL.
INFO [alembic.context] Running upgrade None -> 1975ea83b712
一般我們需要指定版本號進行升級,但是對於最新以及最初版本有兩個額外的別名,head指最新版本,base指最初的版本。
降級也很簡單,只要upgrade以及downgrade實現足夠魯棒。
$ alembic downgrade base
INFO [alembic.context] Context class PostgresqlContext.
INFO [alembic.context] Will assume transactional DDL.
INFO [alembic.context] Running downgrade 1975ea83b712 -> None
自動生成遷移腳本
Alembic 不僅僅能夠維護數據庫歷史版本,而且帶來這個新奇的特性,自動生成遷移腳本。
通常我們進行編碼時候,在確定需求後,通常需要對數據模型進行變化。
不要擔心,只要不是出於技術實現問題,諸如長度過少數據類型應用錯等。而是因爲業務的變更而導致的數據模型變更完全可以理解。"程序=算法+數據結構“,業務邏輯發生了變化,實現算法、數據結構必然發生變化,不要貪圖抽象隔離設計之類云云,這類除了使得程序複雜度增加之外,很難保證未來預期是否如之前所設計的工作量完全可以避免。
口頭商量,確定方案,然後開始打算修改,除了設計稿之外,往往最先實現的是ORM中我們的實體類,因爲他們簡單易懂。
在此例中我因爲需要給用戶添加微博OAuth2.0的綁定,所以新增了兩個字段:
class User(Base):
# …. origin others setting
weibo_token = Column(String(64), nullable=True)
weibo_expires = Column(DateTime, nullable=True)
這個時候直接運行程序必然會失敗,因爲映射關係已經被打亂了,我們需要重建這個關係。
配置YOUR_ALEMBIC_DIR/env.py文件,修改target_metadata = None爲你的元信息對象。
這裏我就直接導入了,但是在導入的過程中由於目錄問題,所以一個額外的Hack。
# Hack for model import
import os
import sys
sys.path.insert(0, os.path.realpath("."))
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import my model
# target_metadata = None
from model import Base
target_metadata = Base.metadata
見證奇蹟的時刻:
$ alembic revision --autogenerate -m "add weibo token fields for user"
INFO [alembic.migration] Context impl MySQLImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate] Detected added column 'user.weibo_expires'
INFO [alembic.autogenerate] Detected added column 'user.weibo_token'
Generating migrate/versions/3117ba3f1f1f_add_weibo_token_expires_for_user.py...done
剩下的就可以按照正常的Alembic操作進行升降級了,是不是把煩人的數據庫結構變更問題解決了?當然,這些問題可能在其他生態圈中根本不是問題(Java/Hibernate,Ruby/RoR)。 別忘了將這些變更提交到VCS中,他們可是非常值得你去維護。
自動遷移腳本生成功能實現
你可以在Alembic的源碼的autogenerate.py模塊中找到,一共近七百行。
程序流程如下: d.png
寫得挺流水的,沒有抽象,至少_compare_*都只是對於兩個集合差集的提取,以及交集的迭代,這部分是可以很容易抽象出來的。
得到差異後,再對差異數據進行“渲染”,既有原地執行,也有渲染輸出爲Sql,還能對升降級進行不同的輸出。
Sqlalchemy-migrate
Sqlalchemy-migrate 借鑑RoR的思路,對數據庫進行版本化管理。但是隻是提供了基本的功能,對於多個數據庫引擎的差異暴露給了開發者,不易用。
命令行的控制細節也挺多了,和Sqlalchemy似乎不是一個思路。 這裏就有一個StackOverflow的用戶在抱怨難以上手。
alembic revision --autogenerate -m "add machine state"
數據庫版本化
通常我們會將我們的代碼放入到某個VCS(版本控制系統)中,進行可追溯的版本管理。一個項目除了代碼,通常還會有一個數據庫,這個數據庫可能會隨着項目的演進發生變化,甚至需要可以回滾到過去的某個狀態,於是一些工具將數據庫的版本化也納入了管理。
Alembic 是 Sqlalchemy 的作者實現的一個數據庫版本化管理工具,它可以對基於Sqlalchemy的Model與數據庫之間的歷史關係進行版本化的維護。
Alembic
你可以通過 pip install alembic 直接安裝,它需要三個依賴包,PIP會自動處理。
SQLAlchemy 同作者的ORM工具
Mako 同作者的模版工具
MarkupSafe 轉換Markup到HTML的組件
初始化
在你的項目根目錄運行
alembic init YOUR_ALEMBIC_DIR
隨後你的項目目錄應該會新增一個alembic.ini文件以及一個YOUR_ALEMBIC_DIR目錄,最好指定一個符合自己項目風格的命名。
接下來的操作都是圍繞這個目錄。
yourproject/
alembic.ini
YOUR_ALEMBIC_DIR/
env.py
README
script.py.mako
versions/
3512b954651e_add_account.py
2b1ae634e5cd_add_order_id.py
3adcc9a56557_rename_username_field.py
alembic.ini 提供了一些基本的配置
env.py 每次執行Alembic都會加載這個模塊,主要提供項目Sqlalchemy Model 的連接
script.py.mako 遷移腳本生成模版
versions 存放生成的遷移腳本目錄
除了基本的Alembic項目之外,你還可以指定幾個特殊的項目模版。
$ alembic list_templates
Available templates:
generic - Generic single-database configuration.
multidb - Rudimentary multi-database configuration.
pylons - Configuration that reads from a Pylons project environment.
Templates are used via the 'init' command, e.g.:
alembic init --template pylons ./scripts
你需要編輯alembic.ini文件去指定Alembic的數據庫連接。
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of auto generate
# revision_environment = false
sqlalchemy.url = driver://user:pass@localhost/dbname
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
版本
首先創建一個基本數據庫版本,你當然可以從已有的數據庫出發。
$ alembic revision -m "create account table"
Generating /path/to/yourproject/YOUR_ALEMBIC_DIR/versions/1975ea83b712_create_accoun
t_table.py...done
生成的版本文件類似於:
"""create account table
Revision ID: 1975ea83b712
Revises: None
Create Date: 2011-11-08 11:40:27.089406
"""
# revision identifiers, used by Alembic.
revision = '1975ea83b712'
down_revision = None
from alembic import op
import sqlalchemy as sa
def upgrade():
pass
def downgrade():
pass
其中 revision = '1975ea83b712'和down_revision = None指定了這個reversion的當前版本號,以及父版本號,就是通過這個進行追溯。
然後我們修改upgrade和downgrade進行實際的升降級操作。通過易用的API,我們只需要對op和sa對象進行操作即可。
def upgrade():
op.create_table(
'account',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('name', sa.String(50), nullable=False),
sa.Column('description', sa.Unicode(200)),
)
def downgrade():
op.drop_table('account')
具體op所支持的操作請看操作API引用。
升級,降級
然後我們更新好最新的版本。
$ alembic upgrade head
INFO [alembic.context] Context class PostgresqlContext.
INFO [alembic.context] Will assume transactional DDL.
INFO [alembic.context] Running upgrade None -> 1975ea83b712
一般我們需要指定版本號進行升級,但是對於最新以及最初版本有兩個額外的別名,head指最新版本,base指最初的版本。
降級也很簡單,只要upgrade以及downgrade實現足夠魯棒。
$ alembic downgrade base
INFO [alembic.context] Context class PostgresqlContext.
INFO [alembic.context] Will assume transactional DDL.
INFO [alembic.context] Running downgrade 1975ea83b712 -> None
自動生成遷移腳本
Alembic 不僅僅能夠維護數據庫歷史版本,而且帶來這個新奇的特性,自動生成遷移腳本。
通常我們進行編碼時候,在確定需求後,通常需要對數據模型進行變化。
不要擔心,只要不是出於技術實現問題,諸如長度過少數據類型應用錯等。而是因爲業務的變更而導致的數據模型變更完全可以理解。"程序=算法+數據結構“,業務邏輯發生了變化,實現算法、數據結構必然發生變化,不要貪圖抽象隔離設計之類云云,這類除了使得程序複雜度增加之外,很難保證未來預期是否如之前所設計的工作量完全可以避免。
口頭商量,確定方案,然後開始打算修改,除了設計稿之外,往往最先實現的是ORM中我們的實體類,因爲他們簡單易懂。
在此例中我因爲需要給用戶添加微博OAuth2.0的綁定,所以新增了兩個字段:
class User(Base):
# …. origin others setting
weibo_token = Column(String(64), nullable=True)
weibo_expires = Column(DateTime, nullable=True)
這個時候直接運行程序必然會失敗,因爲映射關係已經被打亂了,我們需要重建這個關係。
配置YOUR_ALEMBIC_DIR/env.py文件,修改target_metadata = None爲你的元信息對象。
這裏我就直接導入了,但是在導入的過程中由於目錄問題,所以一個額外的Hack。
# Hack for model import
import os
import sys
sys.path.insert(0, os.path.realpath("."))
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import my model
# target_metadata = None
from model import Base
target_metadata = Base.metadata
見證奇蹟的時刻:
$ alembic revision --autogenerate -m "add weibo token fields for user"
INFO [alembic.migration] Context impl MySQLImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate] Detected added column 'user.weibo_expires'
INFO [alembic.autogenerate] Detected added column 'user.weibo_token'
Generating migrate/versions/3117ba3f1f1f_add_weibo_token_expires_for_user.py...done
剩下的就可以按照正常的Alembic操作進行升降級了,是不是把煩人的數據庫結構變更問題解決了?當然,這些問題可能在其他生態圈中根本不是問題(Java/Hibernate,Ruby/RoR)。 別忘了將這些變更提交到VCS中,他們可是非常值得你去維護。
自動遷移腳本生成功能實現
你可以在Alembic的源碼的autogenerate.py模塊中找到,一共近七百行。
程序流程如下: d.png
寫得挺流水的,沒有抽象,至少_compare_*都只是對於兩個集合差集的提取,以及交集的迭代,這部分是可以很容易抽象出來的。
得到差異後,再對差異數據進行“渲染”,既有原地執行,也有渲染輸出爲Sql,還能對升降級進行不同的輸出。
Sqlalchemy-migrate
Sqlalchemy-migrate 借鑑RoR的思路,對數據庫進行版本化管理。但是隻是提供了基本的功能,對於多個數據庫引擎的差異暴露給了開發者,不易用。
命令行的控制細節也挺多了,和Sqlalchemy似乎不是一個思路。 這裏就有一個StackOverflow的用戶在抱怨難以上手。
alembic revision --autogenerate -m "add machine state"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.