在之前的文章中我們或多或少的介紹了關於
Python的知識,並且到了是實戰中,我們就要用
python開發頁面,其實,用
架構開發頁面,是最簡單的,也是最輕鬆的。本章,我們就要介紹
Python頁面開發中的用
orm架構
開發頁面。
什麼是orm
ORM 即Object Relational Mapping,全稱對象關係映射。
可是它到底是幹啥的呢?
如果接觸過一些web背景化,我們知道web後台有很大一部分工作都是資料的增刪改查,如果每次操作資料庫都要串連資料庫,構造sql語句,執行sql語句的話,那未免太麻煩了,所以我們可以將資料庫中的表,欄位,行,與我們的物件導向編程中的類,類的屬性,以及對象建立一一對應的映射關係,這樣我們便可以避免直接操作資料庫,而只要調用相應的方法就可以了。
拿我過去的做法舉個例子就明白了,比如實現一個使用者註冊,以前我是怎麼做的,前台拿到資料,傳給後台,然後後台字串拼接形成sql語句,後台執行。
而有了ORM以後,我只需要用資料執行個體化一個User對象,然後調用該對象的save方法,便儲存到了資料庫,作為使用者的角度,不需要操作一句sql語句。
假設User類對應users表
user=User(id="100001",name="Andy",password="*****")user.save() //儲存到資料庫user=User.findById("100001") #從資料庫中找出id為"100001"的使用者user.update(password="*********") #更改id為"100001"的使用者密碼users=User.findAll() #取出users表中全部資料
我就問,這樣用起來不爽嗎?
注意
IO操作均為非同步,用到的非同步庫為asyncio
連結的資料庫為mysql 5.7,用到的mysql非同步IO驅動為aiomysql
實現ORM的必要準備---封裝資料庫操作
建立資料庫連接池
import asyncioimport aiomysql async def create_pool(**kw):global __pool__pool=await aiomysql.create_pool( host=kw.get('host','localhost'), port=kw.get('port',3306), user=kw['user'], password=kw['password'], db=kw['db'], charset=kw.get('charset','utf8'), autocommit=kw.get('autocommit',True), # 自動認可事務 maxsize=kw.get('maxsize',10), # 池中最多有10個連結化物件 minsize=kw.get('minsize',1),)
封裝select方法
async def select(sql,args,size=None): //size可以決定取幾條global __poolwith (await __pool) as conn: cur=await conn.cursor(aiomysql.DictCursor) # 用參數替換而非字串拼接可以防止sql注入 await cur.execute(sql.replace('?','%s'),args) if size: rs=await cur.fetchmany(size) else: rs=await cur.fetchall() await cur.close() return rs
除了select方法要返回查詢內容,剩下的update,insert,delete均只需返回一個影響行數,所以可將它們三個封裝為一個execute方法
def execute(sql,args):global __pooltry: with (await __pool) as conn: cur=await conn.cursor() await cur.execute(sql.replace('?', '%s'), args) affected=cur.rowcount await cur.close()except BaseException as e: raise ereturn affected
開始動手實現ORM
編程中有個思想叫做”自頂向下“。所以當你對如何設計ORM無從下手的時候,你可以假設已經有一個ORM架構,你想怎麼用?
class Model(object): async def find(self): passclass User(Model): # 注意這裡的都是類屬性 __table__="users" id=StringField(...) name=StringField(...)user=User(id="10001",name="Andy")user.save()
有沒有發現,這樣看User類,很清楚,對應user表,這個表有哪些欄位,一目瞭然。然後讓子類繼承父類,實現對find,save...等方法的複用。真是完美,可是要怎麼實現呢?
欄位類的實現
class Field(object): def __init__(self,name,column_type,primary_key,default): self.name=name # 欄位名 self.column_type=column_type # 欄位資料類型 self.primary_key=primary_key # 是否是主鍵 self.default=default # 有無預設值 def __str__(self): return '<%s:%s>' % (self.__class__.__name__,self.name) class StringField(Field): def __init__(self,name=None,primary_key=False,default=None,ddl='varchar(100)'): super(StringField,self).__init__(name,ddl,primary_key,default) # 其它欄位略,一個道理,一個模式