Python的世界裏有許多web框架:好比大而全的 Django, 提供了模型定義遷移,到路由處理,再到視圖的渲染等整套功能;好比小巧靈活的Flask, 雖然只包含了核心的請求處理內容,但卻能夠經過安裝生態豐富的插件來完成大多數所需功能;好比面向ERP行業的Odoo, 除了基礎的MVC, 還提供了經常使用的進銷存和人力資源等模塊以及方便的web數據管理界面;好比以異步IO爲特點的Sanic 和 Tonado, 提供了一套基於異步IO的請求處理方案;還有其餘Bottle, Cherrypy, Pyramid 等。python
這麼多web框架其中一類是全套web解決方案的,像django,pyramid,odoo等,一類是提供路由和請求處理的"api"微型框架,像flask, sanic, bottle, cherrpy等。當使用到後者這類微型框架時,根據業務場景不一樣,若是須要處理模型的創建、升級和遷移的問題,能夠考慮下接下來要介紹的sqlalchemy 和Alembic。mysql
SQLAlchemy是python裏的處理模ORM(模型關係映射)一套工具,能夠經過直觀地經過定義python中的class來定義數據表結構,經過操做class的具體object來操做數據記錄。 Alembic是一套管理數據庫升降級的遷移工具,好比在實際業務場景中須要對已經定義好的模型進行增刪字段操做,能夠經過alembic來對升降級進行方便地可控地操做。git
SQLAlchemy和alembic的安裝和詳細配置能夠參考官方文檔,這裏我經過一個示例來講明如何實現model的定義和遷移。代碼地址在這裏。github
安裝python依賴(主要是SQLAlchemy和alembic):web
pip install -r requirements.txt
初始化alembic:sql
alembic init YOUR_ALEMBIC_DIR
alembic會在根目錄建立 YOUR_ALEMBIC_DIR
目錄和 alembic.ini
文件,
因此在個人示例代碼裏, alembic_dir
和 alembic.ini
是運行 alembic init alembic_dir
初始化建立的。數據庫
alembic.ini
文件 提供了一些基本的配置,好比數據庫的鏈接選項。django
alembic_dir
的目錄結構和做用爲:flask
$ tree alembic_dir alembic_dir ├── README ├── env.py # 每次執行Alembic都會加載這個模塊,主要提供項目Sqlalchemy Model 的鏈接 ├── script.py.mako # 遷移腳本生成模版 └── versions # 存放生成的遷移腳本目錄 1 directory, 4 files
接下來先來看看sqlalchemy裏model的定義,在model目錄裏:api
$ tree . ├── __init__.py # 打包成一個模塊 ├── base.py # 定義全部模型繼承的Base類 ├── role.py # 定義「角色」模型 └── user.py # 定義「用戶」模型 0 directories, 4 files
其中,sqlalchemy的模型類繼承自一個由 declarative_base()
方法生成的類,因此在 base.py
裏有以下兩行代碼:
from sqlalchemy.ext.declarative import declarative_base Base = declarative_base()
模型定義完成後,咱們須要告訴alembic去哪裏找尋模型定義,因此在 alembic_dir/env.py
的21行左右能夠看到指定:
# Custmosized import os import sys # 將當前目錄(項目更目錄)加入sys.path, 固然也能夠將根目錄下的model加入sys.path,這樣就不須要將model封裝成模塊 sys.path.append(os.getcwd()) from model import Base target_metadata = Base.metadata
另外一般咱們也改一下生成模板 script.py.mako
,加上編碼信息,不然在升級腳本中若是有中文會報錯,參見 alembic_dir/script.py.mako
的前兩行。
接下來須要配置alembic鏈接管理那個數據庫,在 alembic.ini
的第38行修改數據庫鏈接選項,這裏代碼中採用本地的mysql爲示例:
sqlalchemy.url = mysql://root:@localhost/test2
配置工做作完後,確保本地mysql服務啓動,而且有上面配置的數據庫後,讓咱們來生成第一份遷移腳本, 在 sqlalchemy-alembic
目錄下運行:
# 其中 "First create user add role table" 是此次遷移腳本的備註,相似git commit的message alembic revision --autogenerate -m "First create user add role table"
運行完命令後,會發如今 sqlalchemy-alembic/alembic_dir/versions
下生成了一個遷移腳本,遷移腳本的主體是:
def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.create_table('roles', sa.Column('id', sa.Integer(), nullable=False), sa.Column('name', sa.String(), nullable=True), sa.PrimaryKeyConstraint('id') ) op.create_table('user', sa.Column('id', sa.Integer(), nullable=False), sa.Column('username', sa.VARCHAR(length=32), nullable=True), sa.Column('password', sa.VARCHAR(length=32), nullable=True), sa.Column('email', sa.VARCHAR(length=32), nullable=True), sa.PrimaryKeyConstraint('id') ) op.create_index('ix_email_pwd', 'user', ['email', 'password'], unique=False) op.create_index('ix_user_pwd', 'user', ['username', 'password'], unique=False) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_index('ix_user_pwd', table_name='user') op.drop_index('ix_email_pwd', table_name='user') op.drop_table('user') op.drop_table('roles') # ### end Alembic commands ###
能夠發現,是根據model定義的內容,自帶生成的升級和降級代碼,實際項目中須要檢查一下升降級腳本是否有誤。
接下來,在項目根目錄下運行升級命令:
$ alembic upgrade head INFO [alembic.runtime.migration] Context impl MySQLImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.runtime.migration] Running upgrade -> 8deb154aaaa3, First create user add role table
其中 head
表示升級到遷移腳本中最新的版本。
這時候檢查數據庫,能夠發現生成了3張表,升級工做就完成了。
alembic_version # alembic用來追蹤目前數據庫表的版本的表,表的內容只有一行,爲當前版本號,對應於升級腳本上的版本號 roles # 自動生成的表 user # 自動生成的表
接下來,若是對模型有其它改動,好比新增字段等,能夠再次生成遷移腳本,檢查無誤後運行upgrade完成遷移動做。
env.py
裏的 target_metadata
,每次遷移作的事徹底有手動來決定對數據庫操做。alembic downgrade -1
的命令, -1
表明降級到上個版本,也支持其餘參數,具體能夠查詢文檔。