?? ?? ORM,對象關系映射,即Object Relational Mapping的簡稱,通過ORM框架將編程語言中的對象模型與數據庫的關系模型建立映射關系,這樣做的目的:簡化sql語言操作數據庫的繁瑣過程(原生sql的編寫及拼接等),轉而直接使用對象模型來操作數據庫做替代
第一部分
?? ?? SqlAlchemy本身無法直接操作數據庫,它是建立在第三方數據庫API(如python 中的pymysql庫)之上,應用程序調用對象模型進行增刪改查等操作時,將對象轉化成sql語句,然后再通過API調用執行已經轉換好的sql語句
安裝
pip install sqlalchemy
pip install pymysql #這里筆者使用的數據API是pymysql
應用
- 配置及創建數據庫引擎
?? ?? SqlAlchemy 支持間接調用多種數據庫API,根據不能的配置文件調用不同的數據庫API
#常見配置文件:即database url,創建數據庫引擎需要
MySQL-Python:mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
pymysql:mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
MySQL-Connector:mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
cx_Oracle:oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
- 創建數據庫引擎
?? ?? * 注意 *:帶上charset=utf8參數,防止中文亂碼
#初始化數據庫連接
from sqlalchemy import create_engine
url="mysql+pymysql://[賬號]:[密碼]@[主機]:[端口]/[數據庫]?charset=utf8" #這里筆者使用的mysql數據庫,pymysql API與數據庫交互,添加的charset可防止中文亂碼
engine=create_engine(url,echo=False,encoding="utf-8") #url為配置文件,echo調試參數,值為為true打印整個sql執行過程
- 創建會話(session)
?? ?? 通過sessionmaker工廠方法,我們得到一個類,默認返回Session類,也可以自定義Session類
方法:
sessionmaker( bind=None, class_=Session, autoflush=True,autocommit=False,expire_on_commit=True,info=None, **kw)
#示例1:直接調用sessionmaker
from sqlalchemy.orm import sessionmaker
SessionClass=sessionmaker(bind=engine)#利用工廠模式獲取SessionClass
session_obj=SessionClass() #創建session對象,此時已綁定數據庫引擎,但是未關聯任何的對象模型
#示例1:使用scoped_session
from sqlalchemy.orm import scoped_session
SessionClass=scoped_session(sessionmaker(bind=engine))#利用工廠模式獲取SessionClass
session_obj=SessionClass() #創建session對象,此時已綁定數據庫引擎,但是未關聯任何的對象模型
scoped_session VS Session
?? ?? Session:多次創建的Session對象是不同的
?? ?? scoped_session:首先通過sessionmaker工廠創建Session對象,然后對Session對象進行相應的管理(先在Registry中找之前是否創建過Session,若沒有,則創建并注冊,有,則直接返回),這樣的目的:同一個線程維護一個session對象,保證了線程的安全性
- 與數據庫交互
????常用操作:與sql語言一致,主要是增刪改查,接下來就簡要概述這4大類
******* 增 *******
session.add(object) #在數據庫中增加一個對象實例
session.add_all([object]) #在數據庫中增加多個對象實例,參數為列表形式
session.commit() #提交,否則未入口
******* 查 *******
#備注:以下均已object代表對象模型,object.prop代表對象object的prop屬性
session.query(object) #查詢object對應的關系表,相當于select * from tables
session.query(object).first() #查詢結果取第一條,沒有返回none
session.query(object).filter(object.prop) #條件查詢,filter相當于where
session.query(object).order_by(object.prop) #排序,默認升序,降序用desc
session.query(object).order_by(object.prop.desc()).limit(10) #降序,及限制10條
session.query(object.prop.label("別名")).filter(object.prop.like("%同同mony")) #模糊查詢及給字段取別名
#使用聚合函數,sum、count等
from sqlalchemy import func
session.query(func.sum(object.prop).label("別名")
******* 改 *******
session.query(object).filter(object.prop>20).update({"prop1": 'values'})#批量更新,若沒有過濾條件,這更新表中所有記錄
myuser = Session.query(object).filter(object.prop>20).first()
object.prop2= 'value2' #單條更新,可直接修改對象
session.commit()
******* 刪 *******
res = session.query(object).filter(object.prop>20).delete()
session.commit()
第二部分
?? 掌握了基本概念和使用,為了更高效、更快捷將關系表轉化成對象,不得不提sqlacodegen
工具
a.安裝
? ? pip install sqlacodegen
b.使用
??sqlacodegen url [opts]
????這里的url就是sqlalchemy中create_engine使用的參數,但是當賬號密碼含有特殊字符時,同樣的url,在sqlacodegen
命令中會報錯,識別不出賬號、密碼、端口等信息,此時可通過給賬號和密碼加引號解決
????opts:
?????? --tables TABLES 指定表,默認將所有表轉化成對象
?????? --noindexes 忽略索引
?????? --noviews 忽略視圖
?????? --noclasses 不生成類,僅生成表
?????? --outfile OUTFILE 輸出文件
示例:
sqlacodegen --noviews --noconstraints --noclasses --noindexes --outfile 對應py文件路徑 url【同create engine處使用的】
注意 :當賬號和密碼包含特殊字符時,需要用引號,否則自動識別不出賬號、密碼、端口等信息
示例1:
#不使用 `--noclasses`導出的對象
from sqlalchemy import BIGINT, Column, DateTime, Float, String, text
from sqlalchemy.dialects.mysql.types import TINYINT
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
metadata = Base.metadata
class TDeviceActivate(Base):
__tablename__ = 't_device_activate'
id = Column(BIGINT(10), nullable=False)
user_id = Column(BIGINT(10), nullable=False)
device_id = Column(String(32), primary_key=True, nullable=False)
mac = Column(String(30))
uuid = Column(String(32))
firmware_type = Column(String(16), primary_key=True, nullable=False)
activate_time = Column(DateTime, nullable=False)
create_date = Column(DateTime, nullable=False)
ip_address = Column(String(50))
longitude = Column(Float(10))
latitude = Column(Float(10))
expires_time = Column(DateTime)
type = Column(TINYINT(10), server_default=text("'1'"))
示例2
#使用 `--noclasses`參數導出的對象
from sqlalchemy import BIGINT, Column, DateTime, Float, MetaData, String, Table, text
from sqlalchemy.dialects.mysql.types import TINYINT
metadata = MetaData()
t_t_device_activate = Table(
't_device_activate', metadata,
Column('id', BIGINT(10), nullable=False),
Column('user_id', BIGINT(10), nullable=False),
Column('device_id', String(32), primary_key=True, nullable=False),
Column('mac', String(30)),
Column('uuid', String(32)),
Column('firmware_type', String(16), primary_key=True, nullable=False),
Column('activate_time', DateTime, nullable=False),
Column('create_date', DateTime, nullable=False),
Column('ip_address', String(50)),
Column('longitude', Float(10)),
Column('latitude', Float(10)),
Column('expires_time', DateTime),
Column('type', TINYINT(10), server_default=text("'1'"))
)
總結
???? 在UI回歸測試腳本中,通常涉及到與數據庫打交道,開始時候主要使用pymysql API 與數據交互,但是隨著使用頻率的增加,直接書寫sql變得繁瑣,便嘗試使用orm的方式