1. 程式人生 > >Python編寫ORM框架

Python編寫ORM框架

ORM全稱“Object Relational Mapping”,即物件-關係對映,就是把關係資料庫的一行對映為一個物件,也就是一個類對應一個表,這樣,寫程式碼更簡單,不用直接操作SQL語句。

要編寫一個ORM框架,所有的類都只能動態定義,因為只有使用者才能根據表的結構定義出對應的類來,使用 metaclass

編寫底層模組的第一步,就是先把呼叫介面寫出來。比如,使用者如果使用這個ORM框架,想定義一個User類來操作對應的資料庫表User,我們期待他寫出這樣的程式碼,用起來和litepal差不多:

class User(Model):
    id = IntegerField("id"
) username = StringField("username") password = StringField("password") email = StringField("email") # 建立例項 u = User(id=1, username= "TaoYuan", password="123456", email="[email protected]") u.save() # 儲存到資料庫

其中,父類Model和屬性型別StringField、IntegerField是由ORM框架提供的,剩下的魔術方法比如save()全部由metaclass自動完成。雖然metaclass的編寫會比較複雜,但ORM的使用者用起來卻異常簡單。

實現

首先來定義Field類,它負責儲存資料庫表的欄位名和欄位型別:

class Field(object):
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type

    def __str__(self,):
        return "<%s:%s>" % (self.__class__.__name__, self.name)

在Field的基礎上,進一步定義各種型別的Field,比如StringField,IntegerField等等:

class IntegerField(Field):
    def __init__(self, name):
        super(IntegerField, self).__init__(name, "bigint")


class StringField(Field):
    def __init__(self, name):
        super(StringField, self).__init__(name, "varchar(20)")

就是編寫最複雜的ModelMetaclass以及Model了:

class ModelMetaclass(type):
    def __new__(mcs, name, bases, attrs):
        if name == "Model":
            return type.__new__(mcs, name, bases, attrs)
        print("Found Model:%s" % name)
        mappings = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                print("Found mappings:%s --> %s" % (k, v))
                mappings[k] = v
        for k in mappings.keys():
            attrs.pop(k)
        attrs['__mappings__'] = mappings  # 儲存屬性和列的對映關係
        attrs['__table__'] = name  # 假設表名和類名一致
        return type.__new__(mcs, name, bases, attrs)


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"'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):  # set
        self[key] = value

    def save(self):  # 儲存
        fields = []
        params = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))

        # 連線資料庫驅動即可真正連線
        sql = "insert into %s (%s) values (%s)" % (self.__table__, ','.join(fields), ','.join(params))
        print('SQL: %s' % sql)
        print('ARGS: %s' % str(args))

    def delete(self):  # 刪
        # 連線資料庫驅動即可真正連線
        sql = "delete from %s" % self.__table__
        print('SQL: %s' % sql)

    def update(self):  # 改
        fields = []
        params = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))

        # 連線資料庫驅動即可真正連線
        sql = "update %s set %s=%s" % (self.__table__, ','.join(fields), ','.join(params))
        print('SQL: %s' % sql)
        print('ARGS: %s' % str(args))

    def find(self):  # 查
        # 連線資料庫驅動即可真正連線
        sql = "select * from %s" % self.__table__
        print('SQL: %s' % sql)

當用戶定義一個class User(Model)時,Python直譯器首先在當前類User的定義中查詢metaclass,如果沒有找到,就繼續在父類Model中查詢metaclass,找到了,就使用Model中定義的metaclassModelMetaclass來建立User類,也就是說,metaclass可以隱式地繼承到子類,但子類自己卻感覺不到。

ModelMetaclass中,一共做了幾件事情:

  1. 排除掉對Model類的修改;
  2. 在當前類(比如User)中查詢定義的類的所有屬性,如果找到一個Field屬性,就把它儲存到一個__mappings__的dict中,同時從類屬性中刪除該Field屬性,否則,容易造成執行時錯誤(例項的屬性會遮蓋類的同名屬性);
  3. 把表名儲存到__table__中,這裡簡化為表名預設為類名。

Model類中,就可以定義各種操作資料庫的方法,比如save()delete()find()update等等。

我們實現了save()方法,把一個例項儲存到資料庫中。因為有表名,屬性到欄位的對映和屬性值的集合,就可以構造出INSERT語句。

得到輸出:

Found Model:User
Found mappings:id --> <IntegerField:id>
Found mappings:username --> <StringField:username>
Found mappings:password --> <StringField:password>
Found mappings:email --> <StringField:email>
SQL: insert into User (id,username,password,email) values (?,?,?,?)
ARGS: [1, 'TaoYuan', '123456', '[email protected]']
------------------------------
SQL: delete from User
------------------------------
SQL: update User set id,username,password,email=?,?,?,?
ARGS: [1, 'TaoYuan', '123456', '[email protected]']
------------------------------
SQL: select * from User

小結

metaclass是Python中非常具有魔術性的物件,它可以改變類建立時的行為。這種強大的功能使用起來務必小心。

相關推薦

Python編寫ORM框架

ORM全稱“Object Relational Mapping”,即物件-關係對映,就是把關係資料庫的一行對映為一個物件,也就是一個類對應一個表,這樣,寫程式碼更簡單,不用直接操作SQL語句。 要編寫一個ORM框架,所有的類都只能動態定義,因為只有使用者才能根

Python中的元類編寫ORM框架

部落格轉載: https://blog.csdn.net/givemefive_y/article/details/79806348 https://blog.csdn.net/eye_water/article/details/78777870 https://www.liaoxue

PythonORM框架SQLAlchemy使用入門(一)

不要放棄你的幻想。當幻想沒有的時候,你還可以生存,但是你雖生猶死。 建立實體類,生成資料庫架構 import os import sys from sqlalchemy import Col

編寫ORM框架

ORM:Object-Relational Mapping,把關係資料庫中的表結構對映到物件上。然後操作資料庫就不需要構造SQL語句,而是直接呼叫相應的方法。ORM框架可以方便的完成這些轉換,然後,資料庫表中的一行記錄就對應著python中的一個物件,就不需要使

推薦pythonORM框架peewee(轉)

以下是自己在一些專案中的簡單心得,無他,旨在向一些不瞭解peewee的新手推薦一個順手的工具,提供開發效率。至於具體使用細節,官方文件還是讀一下吧,簡單的文字。 熟手跳過。 你操作資料庫時在用繁瑣難維護的SQL?還是笨重複雜的SqlAlchemy?或者是你運氣夠好使用DJANGO而享受其ORM? 我曾經也是

深入理解Java的Annotation系列-第五部分 使用註解編寫ORM框架

一、什麼是ORM? 物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/Rmapping),是一種程式技術,隨著面向物件的發展而產生的。用來把物件模型表示的物件對映到基於S Q L 的關係模型資料庫結構中去,或者把表中的

Python ORM框架之 Peewee入門

lob shortcuts pymysql 主鍵 也會 roo username fault 有意思   之前在學Django時,發現它的模型層非常好用,把對數據庫的操作映射成對類、對象的操作,避免了我們直接寫在Web項目中SQL語句,當時想,如果這個模型層可以獨立出來使用

python——type()、metaclass元類和精簡ORM框架

定制 定義 attribute varchar elm cep 實例 編寫代碼 __main__ 1、type()函數 #type()函數既可以返回一個對象的類型,又可以創建出新的類型, # 比如,我們可以通過type()函數創建出Hello類,而無需通過cl

python(十二)下:ORM框架SQLAlchemy使用學習

func column bar 插入數據 ref min 統計 就是 連接 此出處:http://blog.csdn.net/fgf00/article/details/52949973 本節內容 ORM介紹 sqlalchemy安裝 sqlalchemy

我的第一個python web開發框架(24)——系統重構與ORM

內容 版權 質量 重寫 很多 掌握 orm .... 最重要的   小白弄完代碼版本管理和接口文檔後,興奮的找到老菜。   小白:老大,我已經按你講的要求,將代碼版本管理和接口文檔都搞好了。從項目開始到現在,除了代碼編寫,感覺學會好多東西啊。   老菜:嗯嗯,實戰確實需

6、第八周 - 網絡編程進階 - Python語言下的SqlAlchemy ORM框架應用

() bind chan base pymysql commit 提交 輸出 echo Mysql SqlAlchemy 基本步驟 1、SqlAlchemy 基本結構語法如下: 案例: from sqlalchemy import create_engine,Colu

Python中Web框架編寫學習心得

記錄日誌 實例 心得 ret NPU oba esp ascii edi 學習廖雪峰老師的Python實戰教程,在Web框架這部分看了大致一個多禮拜,前面的知識學的不夠紮實,由於比較復雜,因此在這裏總結下,也算是鞏固了。 先看下框架的調用代碼: app = web.Ap

[python] 理解metaclass並實現一個簡單ORM框架

lds asc into password 這樣的 內容 建行 ati 什麽 metaclass 除了使用type()動態創建類以外,要控制類的創建行為,還可以使用metaclass。 metaclass,直譯為元類,簡單的解釋就是: 當我們定義了類以後,就可以根據這個

python ORM 框架 sqlalchemy

sqlalchemy 是一款Python語言寫的ORM框架, 該框架建立在資料庫API基礎之上。   sqlalchemy 本身無法操作資料庫,必須已第三方外掛為基礎,Dialect用於和資料API進行交流,根據不通的的配置呼叫不通的資料庫API,從而實現對資料庫的操作。

SQLAlchemy 1.2.15 釋出,Python ORM 框架

   SQLAlchemy 1.2.15 釋出了,SQLAlchemy 是一個 Python 的 SQL 工具包以及資料庫物件關係對映框架。它包含整套企業級持久化模式,專門用於高效和高效能的資料庫訪問。 此版本包含了各種 ORM 級的修復,其中包括 1.2.13 中的

Python ORM框架Pony —— 什麼是Pony ORM

Pony是一種高階的物件關係對映器。ORM允許開發人員以物件的形式處理資料庫的內容。關係資料庫包含儲存在表中的行。但是,當使用高階面嚮物件語言編寫程式時,可以以物件的形式訪問從資料庫檢索的資料,這樣十分方便。Pony ORM是一個Python語言庫,允許您方便地處理在關係資料庫中儲存為行的物件。

python的Pony ORM框架總結

最近學校裡辦了python興趣班,剛學完python的基礎語法就講了這個Pony框架,以下是我上課記錄的某些關鍵點的筆記 Python 2提供了兩種字串型別 - str(位元組字串)和unicode(unicode字串),而在Python 3中,str型別表示unicode字串,並且剛剛刪除了u

Python ORM框架Pony —— Pony入門

安裝 要安裝Pony我們首先要安裝好pip,假設我們已經安裝完成pip,請在dos命令視窗下鍵入以下命令: pip install pony 之後pip會自動將我們的Pony安裝到Python 2.7或Python 3上 要確保已成功安裝Pony,請以互動方式啟動Python編譯器並

一個用Python編寫的股票資料(滬深)爬蟲和選股策略測試框架

一個股票資料(滬深)爬蟲和選股策略測試框架,資料基於雅虎YQL和新浪財經。 根據選定的日期範圍抓取所有滬深兩市股票的行情資料。 根據指定的選股策略和指定的日期進行選股測試。 計算選股測試實際結果(包括與滬深300指數比較)。 儲存資料到JSON檔案、CS

python之Django框架篇-路由系統,檢視,模板,ORM複習

1. Urls.py 路由系統: 正則 分組匹配 --> 位置引數 分組命名匹配 --> 關鍵字引數 分級路由 include 給路由起別名 name="xx" 反向解析url view