Python中編寫ORM框架的入門指引
有了db模塊,操作數(shù)據(jù)庫直接寫SQL就很方便。但是,我們還缺少ORM。如果有了ORM,就可以用類似這樣的語句獲取User對象:
user = User.get('123')
而不是寫SQL然后再轉(zhuǎn)換成User對象:
u = db.select_one('select * from users where id=?', '123') user = User(**u)
所以我們開始編寫ORM模塊:transwarp.orm。
設(shè)計(jì)ORM接口
和設(shè)計(jì)db模塊類似,設(shè)計(jì)ORM也是從上層調(diào)用者角度來設(shè)計(jì)。
我們先考慮如何定義一個User對象,然后把數(shù)據(jù)庫表users和它關(guān)聯(lián)起來。
from transwarp.orm import Model, StringField, IntegerField class User(Model): __table__ = 'users' id = IntegerField(primary_key=True) name = StringField()
注意到定義在User類中的__table__、id和name是類的屬性,不是實(shí)例的屬性。所以,在類級別上定義的屬性用來描述User對象和表的映射關(guān)系,而實(shí)例屬性必須通過__init__()方法去初始化,所以兩者互不干擾:
# 創(chuàng)建實(shí)例: user = User(id=123, name='Michael') # 存入數(shù)據(jù)庫: user.insert()
實(shí)現(xiàn)ORM模塊
有了定義,我們就可以開始實(shí)現(xiàn)ORM模塊。
首先要定義的是所有ORM映射的基類Model:
class Model(dict): __metaclass__ = ModelMetaclass def __init__(self, **kw): super(Model, self).__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'Dict' object has no attribute '%s'" % key) def __setattr__(self, key, value): self[key] = value
Model從dict繼承,所以具備所有dict的功能,同時又實(shí)現(xiàn)了特殊方法__getattr__()和__setattr__(),所以又可以像引用普通字段那樣寫:
>>> user['id'] 123 >>> user.id 123
Model只是一個基類,如何將具體的子類如User的映射信息讀取出來呢?答案就是通過metaclass:ModelMetaclass:
class ModelMetaclass(type): def __new__(cls, name, bases, attrs): mapping = ... # 讀取cls的Field字段 primary_key = ... # 查找primary_key字段 __table__ = cls.__talbe__ # 讀取cls的__table__字段 # 給cls增加一些字段: attrs['__mapping__'] = mapping attrs['__primary_key__'] = __primary_key__ attrs['__table__'] = __table__ return type.__new__(cls, name, bases, attrs)
這樣,任何繼承自Model的類(比如User),會自動通過ModelMetaclass掃描映射關(guān)系,并存儲到自身的class中。
然后,我們往Model類添加class方法,就可以讓所有子類調(diào)用class方法:
class Model(dict): ... @classmethod def get(cls, pk): d = db.select_one('select * from %s where %s=?' % (cls.__table__, cls.__primary_key__.name), pk) return cls(**d) if d else None
User類就可以通過類方法實(shí)現(xiàn)主鍵查找:
user = User.get('123')
往Model類添加實(shí)例方法,就可以讓所有子類調(diào)用實(shí)例方法:
class Model(dict): ... def insert(self): params = {} for k, v in self.__mappings__.iteritems(): params[v.name] = getattr(self, k) db.insert(self.__table__, **params) return self
這樣,就可以把一個User實(shí)例存入數(shù)據(jù)庫:
user = User(id=123, name='Michael') user.insert()
最后一步是完善ORM,對于查找,我們可以實(shí)現(xiàn)以下方法:
find_first() find_all() find_by()
對于count,可以實(shí)現(xiàn):
count_all() count_by()
以及update()和delete()方法。
最后看看我們實(shí)現(xiàn)的ORM模塊一共多少行代碼?加上注釋和doctest才僅僅300多行。用Python寫一個ORM是不是很容易呢?
- Python流行ORM框架sqlalchemy安裝與使用教程
- Python的ORM框架SQLAlchemy入門教程
- Python ORM框架SQLAlchemy學(xué)習(xí)筆記之?dāng)?shù)據(jù)添加和事務(wù)回滾介紹
- Python ORM框架SQLAlchemy學(xué)習(xí)筆記之安裝和簡單查詢實(shí)例
- Python ORM框架SQLAlchemy學(xué)習(xí)筆記之?dāng)?shù)據(jù)查詢實(shí)例
- Python ORM框架SQLAlchemy學(xué)習(xí)筆記之關(guān)系映射實(shí)例
- Python輕量級ORM框架Peewee訪問sqlite數(shù)據(jù)庫的方法詳解
- Python的ORM框架中SQLAlchemy庫的查詢操作的教程
- Python ORM框架SQLAlchemy學(xué)習(xí)筆記之映射類使用實(shí)例和Session會話介紹
- Python利用sqlacodegen自動生成ORM實(shí)體類示例
相關(guān)文章
一個基于flask的web應(yīng)用誕生 flask和mysql相連(4)
一個基于flask的web應(yīng)用誕生第四篇,這篇文章主要介紹了如何讓flask和mysql進(jìn)行互聯(lián),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04python和mysql交互操作實(shí)例詳解【基于pymysql庫】
這篇文章主要介紹了python和mysql交互操作,結(jié)合實(shí)例形式詳細(xì)分析了Python基于pymysql庫實(shí)現(xiàn)mysql數(shù)據(jù)庫的連接、增刪改查等各種常見操作技巧,需要的朋友可以參考下2019-06-06django認(rèn)證系統(tǒng)實(shí)現(xiàn)自定義權(quán)限管理的方法
這篇文章主要介紹了django認(rèn)證系統(tǒng)實(shí)現(xiàn)自定義權(quán)限管理的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07Python 實(shí)現(xiàn)兩個列表里元素對應(yīng)相乘的方法
今天小編就為大家分享一篇Python 實(shí)現(xiàn)兩個列表里元素對應(yīng)相乘的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11Python函數(shù)式編程指南(二):從函數(shù)開始
這篇文章主要介紹了Python函數(shù)式編程指南(二):從函數(shù)開始,本文講解了定義一個函數(shù)、使用函數(shù)賦值、閉包、作為參數(shù)等內(nèi)容,需要的朋友可以參考下2015-06-06詳解tf.device()指定tensorflow運(yùn)行的GPU或CPU設(shè)備實(shí)現(xiàn)
這篇文章主要介紹了詳解tf.device()指定tensorflow運(yùn)行的GPU或CPU設(shè)備實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02