python ORM框架:SqlAlchemy

?? ?? ORM,對象關(guān)系映射庙洼,即Object Relational Mapping的簡稱岖是,通過ORM框架將編程語言中的對象模型與數(shù)據(jù)庫的關(guān)系模型建立映射關(guān)系运准,這樣做的目的:簡化sql語言操作數(shù)據(jù)庫的繁瑣過程(原生sql的編寫及拼接等)涩堤,轉(zhuǎn)而直接使用對象模型來操作數(shù)據(jù)庫做替代

第一部分

?? ?? SqlAlchemy本身無法直接操作數(shù)據(jù)庫胚膊,它是建立在第三方數(shù)據(jù)庫API(如python 中的pymysql庫)之上故俐,應(yīng)用程序調(diào)用對象模型進(jìn)行增刪改查等操作時,將對象轉(zhuǎn)化成sql語句紊婉,然后再通過API調(diào)用執(zhí)行已經(jīng)轉(zhuǎn)換好的sql語句

安裝

  pip install sqlalchemy
  pip install pymysql #這里筆者使用的數(shù)據(jù)API是pymysql

應(yīng)用

- 配置及創(chuàng)建數(shù)據(jù)庫引擎

?? ?? SqlAlchemy 支持間接調(diào)用多種數(shù)據(jù)庫API药版,根據(jù)不能的配置文件調(diào)用不同的數(shù)據(jù)庫API

#常見配置文件:即database url,創(chuàng)建數(shù)據(jù)庫引擎需要
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...]
- 創(chuàng)建數(shù)據(jù)庫引擎

?? ?? * 注意 *:帶上charset=utf8參數(shù)喻犁,防止中文亂碼

#初始化數(shù)據(jù)庫連接
from sqlalchemy import create_engine
url="mysql+pymysql://[賬號]:[密碼]@[主機]:[端口]/[數(shù)據(jù)庫]?charset=utf8" #這里筆者使用的mysql數(shù)據(jù)庫槽片,pymysql API與數(shù)據(jù)庫交互,添加的charset可防止中文亂碼
engine=create_engine(url,echo=False,encoding="utf-8")  #url為配置文件,echo調(diào)試參數(shù)肢础,值為為true打印整個sql執(zhí)行過程
- 創(chuàng)建會話(session)

?? ?? 通過sessionmaker工廠方法还栓,我們得到一個類,默認(rèn)返回Session類传轰,也可以自定義Session類
方法:
sessionmaker( bind=None, class_=Session, autoflush=True,autocommit=False,expire_on_commit=True,info=None, **kw)

#示例1:直接調(diào)用sessionmaker
from sqlalchemy.orm import sessionmaker
SessionClass=sessionmaker(bind=engine)#利用工廠模式獲取SessionClass
session_obj=SessionClass() #創(chuàng)建session對象,此時已綁定數(shù)據(jù)庫引擎蝙云,但是未關(guān)聯(lián)任何的對象模型
#示例1:使用scoped_session
from sqlalchemy.orm import scoped_session
SessionClass=scoped_session(sessionmaker(bind=engine))#利用工廠模式獲取SessionClass
session_obj=SessionClass() #創(chuàng)建session對象,此時已綁定數(shù)據(jù)庫引擎,但是未關(guān)聯(lián)任何的對象模型

scoped_session VS Session
?? ?? Session:多次創(chuàng)建的Session對象是不同的
?? ?? scoped_session:首先通過sessionmaker工廠創(chuàng)建Session對象路召,然后對Session對象進(jìn)行相應(yīng)的管理(先在Registry中找之前是否創(chuàng)建過Session勃刨,若沒有波材,則創(chuàng)建并注冊,有身隐,則直接返回)廷区,這樣的目的:同一個線程維護(hù)一個session對象,保證了線程的安全性

- 與數(shù)據(jù)庫交互

????常用操作:與sql語言一致贾铝,主要是增刪改查隙轻,接下來就簡要概述這4大類

******* 增 *******

session.add(object) #在數(shù)據(jù)庫中增加一個對象實例
session.add_all([object]) #在數(shù)據(jù)庫中增加多個對象實例,參數(shù)為列表形式
session.commit() #提交,否則未入口

******* 查 *******

#備注:以下均已object代表對象模型垢揩,object.prop代表對象object的prop屬性
session.query(object) #查詢object對應(yīng)的關(guān)系表玖绿,相當(dāng)于select * from tables
session.query(object).first() #查詢結(jié)果取第一條,沒有返回none
session.query(object).filter(object.prop) #條件查詢叁巨,filter相當(dāng)于where
session.query(object).order_by(object.prop) #排序斑匪,默認(rèn)升序,降序用desc
session.query(object).order_by(object.prop.desc()).limit(10) #降序锋勺,及限制10條
session.query(object.prop.label("別名")).filter(object.prop.like("%同同mony")) #模糊查詢及給字段取別名
#使用聚合函數(shù)蚀瘸,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()  

第二部分

?? 掌握了基本概念和使用苏章,為了更高效寂嘉、更快捷將關(guān)系表轉(zhuǎn)化成對象,不得不提sqlacodegen工具
a.安裝
? ? pip install sqlacodegen
b.使用
??sqlacodegen url [opts]
????這里的url就是sqlalchemy中create_engine使用的參數(shù)枫绅,但是當(dāng)賬號密碼含有特殊字符時泉孩,同樣的url,在sqlacodegen命令中會報錯撑瞧,識別不出賬號棵譬、密碼显蝌、端口等信息预伺,此時可通過給賬號和密碼加引號解決
????opts:
?????? --tables TABLES 指定表,默認(rèn)將所有表轉(zhuǎn)化成對象
?????? --noindexes 忽略索引
?????? --noviews 忽略視圖
?????? --noclasses 不生成類曼尊,僅生成表
?????? --outfile OUTFILE 輸出文件
示例:
sqlacodegen --noviews --noconstraints --noclasses --noindexes --outfile 對應(yīng)py文件路徑 url【同create engine處使用的】
注意 :當(dāng)賬號和密碼包含特殊字符時酬诀,需要用引號,否則自動識別不出賬號骆撇、密碼瞒御、端口等信息

示例1:

#不使用 `--noclasses`導(dǎo)出的對象
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`參數(shù)導(dǎo)出的對象
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'"))
)

總結(jié)

???? 在UI回歸測試腳本中,通常涉及到與數(shù)據(jù)庫打交道神郊,開始時候主要使用pymysql API 與數(shù)據(jù)交互肴裙,但是隨著使用頻率的增加趾唱,直接書寫sql變得繁瑣,便嘗試使用orm的方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜻懦,一起剝皮案震驚了整個濱河市甜癞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宛乃,老刑警劉巖悠咱,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異征炼,居然都是意外死亡析既,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人誓焦,你說我怎么就攤上這事慷彤。” “怎么了偷遗?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我囤屹,道長,這世上最難降的妖魔是什么逢渔? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任肋坚,我火速辦了婚禮,結(jié)果婚禮上肃廓,老公的妹妹穿的比我還像新娘智厌。我一直安慰自己,他們只是感情好盲赊,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布铣鹏。 她就那樣靜靜地躺著,像睡著了一般哀蘑。 火紅的嫁衣襯著肌膚如雪诚卸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天绘迁,我揣著相機與錄音合溺,去河邊找鬼。 笑死缀台,一個胖子當(dāng)著我的面吹牛棠赛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼睛约,長吁一口氣:“原來是場噩夢啊……” “哼鼎俘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辩涝,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤而芥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后膀值,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棍丐,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年沧踏,在試婚紗的時候發(fā)現(xiàn)自己被綠了歌逢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡翘狱,死狀恐怖秘案,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情潦匈,我是刑警寧澤阱高,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站茬缩,受9級特大地震影響赤惊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凰锡,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一未舟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧掂为,春花似錦裕膀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至欲诺,卻和暖如春抄谐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瞧栗。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工斯稳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留海铆,地道東北人迹恐。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像卧斟,于是被迫代替她去往敵國和親殴边。 傳聞我的和親對象是個殘疾皇子憎茂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容