Python數據模型構建和遷移方案:SQLAlchemy&Alembic

背景

Python的世界裏有許多web框架:好比大而全的 Django, 提供了模型定義遷移,到路由處理,再到視圖的渲染等整套功能;好比小巧靈活的Flask, 雖然只包含了核心的請求處理內容,但卻能夠經過安裝生態豐富的插件來完成大多數所需功能;好比面向ERP行業的Odoo, 除了基礎的MVC, 還提供了經常使用的進銷存和人力資源等模塊以及方便的web數據管理界面;好比以異步IO爲特點的SanicTonado, 提供了一套基於異步IO的請求處理方案;還有其餘Bottle, Cherrypy, Pyramid 等。python

這麼多web框架其中一類是全套web解決方案的,像django,pyramid,odoo等,一類是提供路由和請求處理的"api"微型框架,像flask, sanic, bottle, cherrpy等。當使用到後者這類微型框架時,根據業務場景不一樣,若是須要處理模型的創建、升級和遷移的問題,能夠考慮下接下來要介紹的sqlalchemyAlembicmysql

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_diralembic.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完成遷移動做。

其它

  • alembic的遷移腳本也是能夠本身手寫的,這樣不須要配置 env.py 裏的 target_metadata ,每次遷移作的事徹底有手動來決定對數據庫操做。
  • alembic的降級能夠用相似 alembic downgrade -1 的命令, -1 表明降級到上個版本,也支持其餘參數,具體能夠查詢文檔。
  • sqlalchemy 能夠以ORM的方式在業務邏輯處理的時候引用,這樣每次查詢到一條或多條數據,就能夠獲得一個或多個對象,相似於django的model。
  • 在使用相似sanic這樣的異步框架時,須要注意orm的選取,是否須要一個異步的orm框架呢,能夠考慮的異步orm能夠參照這裏 ,另外sqlalchemy的做者在15年對此有思考,這篇文章 能夠看看。而我在使用sanic的實際項目中是操做的原生sql,異步io類型的orm配合使用留待之後探究。
相關文章
相關標籤/搜索