Python不使用元類的ORM實現

不使用元類的簡單ORM實現

在 Python 中,ORM(Object-Relational Mapping)是一種將對象和數據庫之間的映射關系進行轉換的技術,使得通過面向對象的方式來操作數據庫更加方便。通常,我們使用元類(metaclass)來實現ORM,但是本文將介紹一種不使用元類的簡單ORM實現方式。

Field類

首先,我們定義一個Field類,用于表示數據庫表中的字段。這個類包含字段的名稱和類型等信息,并且支持一些比較操作,以便后續構建查詢條件。

class Field:def __init__(self, **kwargs):self.name = kwargs.get('name')self.column_type = kwargs.get('column_type')def __eq__(self, other):return Compare(self, '=', other)# 其他比較操作略...

Compare類

為了構建查詢條件,我們引入了一個Compare類,用于表示字段之間的比較關系。它可以支持鏈式操作,構建復雜的查詢條件。

class Compare:def __init__(self, left: Field, operation: str, right: Any):self.condition = f'`{left.name}` {operation} "{right}"'def __or__(self, other: "Compare"):self.condition = f'({self.condition}) OR ({other.condition})'return selfdef __and__(self, other: "Compare"):self.condition = f'({self.condition}) AND ({other.condition})'return self

Model類

接下來,我們定義Model類,表示數據庫中的表。該類通過Field類的實例來定義表的字段,并提供了插入數據的方法。

class Model:def __init__(self, **kwargs):_meta = self.get_class_meta()for k, v in kwargs.items():if k in _meta:self.__dict__[k] = v@classmethoddef get_class_meta(cls) -> Dict:if hasattr(cls, '_meta'):return cls.__dict__['_meta']_meta = {}for k, v in cls.__dict__.items():if isinstance(v, Field):if v.name is None:v.name = kname = v.name_meta[k] = (name, v)table = cls.__dict__.get('__table__')table = cls.__name__ if table is None else table_meta['__table__'] = tablesetattr(cls, '_meta', _meta)return _metadef insert(self):_meta = self.get_class_meta()column_li = []val_li = []for k, v in self.__dict__.items():field_tuple = _meta.get(k)if field_tuple:column, field = field_tuplecolumn_li.append(column)val = str(v) if field.column_type == 'INT' else f'"{str(v)}"'val_li.append(val)sql = f'INSERT INTO {_meta["__table__"]} ({",".join(column_li)}) VALUES ({",".join(val_li)});'print(sql)

Query類

最后,我們實現了Query類,用于構建數據庫查詢。這個類支持鏈式調用,可以設置查詢條件、排序等。

class Query:def __init__(self, cls: Model):self._model = clsself._order_columns = Noneself._desc = ''self._meta = self._model.get_class_meta()self._compare = Noneself.sql = ''def _get(self) -> str:sql = ''if self._compare:sql += f' WHERE {self._compare.condition}'if self._order_columns:sql += f' ORDER BY {self._order_columns}'sql += f' {self._desc}'return sqldef get(self, *args: Field) -> List[Model]:sql = self._get()table = self._meta['__table__']column_li = []if len(args) > 0:for field in args:column_li.append(f'`{field.name}`')else:for v in self._meta.values():if type(v) == tuple and isinstance(v[1], Field):column_li.append(f'`{v[0]}`')columns = ",".join(column_li)sql = f'SELECT {columns} FROM {table} {sql}'self.sql = sqlprint(self.sql)def order_by(self, columns: Union[List, str], desc: bool = False) -> "Query":if isinstance(columns, str):self._order_columns = f'`{columns}`'elif isinstance(columns, list):self._order_columns = ','.join([f'`{x}`' for x in columns])self._desc = 'DESC' if desc else ''return selfdef where(self, compare: "Compare") -> "Query":self._compare = comparereturn self

示例使用

現在,我們可以定義一個模型類,并使用這個簡單的ORM實現進行數據操作。

class User(Model):name = Field()age = Field()# 插入數據
user = User(name='Tom', age=24)
user.insert()# 構建查詢條件并查詢數據
User.query().where((User.name == 'Tom') & (User.age >= 20)).order_by('age').get()

這樣,我們就完成了一個不使用元類的簡單ORM實現。盡管相較于使用元類的方式,代碼結構更為簡單,但在實際應用中,根據項目需求和團隊的約定,選擇合適的實現方式是很重要的。
我們已經介紹了一個基于 Python 的簡單 ORM 實現,它不依賴于元類。在這一部分,我們將繼續探討這個實現,深入了解查詢構建和更復雜的用法。

擴展查詢功能

我們的查詢功能還比較簡單,為了更好地支持復雜查詢,我們可以添加更多的查詢方法和條件。

支持 LIMIT 和 OFFSET

class Query:# ...def limit(self, num: int) -> "Query":self.sql += f' LIMIT {num}'return selfdef offset(self, num: int) -> "Query":self.sql += f' OFFSET {num}'return self

支持 GROUP BY 和 HAVING

class Query:# ...def group_by(self, columns: Union[List, str]) -> "Query":if isinstance(columns, str):columns = [columns]self.sql += f' GROUP BY {",".join([f"`{x}`" for x in columns])}'return selfdef having(self, condition: Compare) -> "Query":self.sql += f' HAVING {condition.condition}'return self

示例用法

class User(Model):name = Field()age = Field()# 插入數據
user = User(name='Tom', age=24)
user.insert()# 構建查詢條件并查詢數據
query = User.query().where((User.name == 'Tom') & (User.age >= 20)).order_by('age').limit(1).offset(0)
query.get(User.name, User.age)  # 僅查詢指定字段# 更復雜的查詢
query = User.query().group_by('age').having((User.age > 20) & (User.age < 30)).order_by('age').limit(10).offset(0)
query.get(User.age, User.count(User.name))  # 查詢年齡在20到30之間的用戶數量

通過引入額外的查詢功能,我們使得這個簡單的 ORM 實現更加強大和靈活。

總結

在這個系列的文章中,我們通過不使用元類的方式,實現了一個簡單的 Python ORM。我們定義了?Field?類表示數據庫字段,Model?類表示數據庫表,以及?Query?類用于構建和執行查詢。通過這個實現,我們可以方便地進行數據操作,構建靈活的查詢條件,而不需要深入理解元類的概念。

然而,這個簡單的 ORM 仍然有一些局限性,例如不支持復雜的表關聯等功能。在實際項目中,選擇使用元類的 ORM 實現或其他成熟的 ORM 框架取決于項目的需求和團隊的技術選型。希望這個實現能夠為你提供一種不同的思路,促使更多的思考和探討。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/42884.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42884.shtml
英文地址,請注明出處:http://en.pswp.cn/web/42884.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

關于go和rust語言的對比

文章目錄 前言Rust 的優勢&#xff1a;Go 的優勢&#xff1a;總結 前言 Go 和 Rust 是兩種現代的系統級編程語言&#xff0c;它們各自擁有獨特的特性和應用場景。以下是它們的一些主要區別&#xff1a; Rust 的優勢&#xff1a; 內存安全&#xff1a;Rust 引入了所有權和借用…

香橙派5plus上跑云手機方案二 waydroid

前言 上篇文章香橙派5plus上跑云手機方案一 redroid(帶硬件加速)說了怎么跑帶GPU加速的redroid方案&#xff0c;這篇說下怎么在香橙派下使用Waydroid。 溫馨提示 雖然能運行&#xff0c;但是體驗下來只能用軟件加速&#xff0c;無法使用GPU加速&#xff0c;所有會很卡。而且…

Pat乙級題解

文章目錄 1~2021 ~ 4041~6061~8081~100101~125 1~20 1001 害死人不償命的(3n1)猜想 B1002 寫出這個數 (20 分) B1003 我要通過&#xff01; B1004 成績排名 1005 繼續(3n1)猜想 B1006 換個格式輸出整數 B1007 素數對猜想 1008 數組元素循環右移問題 B1009 說反話 1010 一元多項…

linux磁盤分區管理

首先關機狀態下&#xff0c;先配置硬盤 硬盤分區管理 識別硬盤 》分區規劃 》 格式化 》 掛載使用 [rootlocalhost ~]# lsblk 查看硬盤 分區劃分&#xff08;m幫助, p 查看分區, n 創建分區, d 刪除分區, q 退出, w 保存&#xff0c; g gpt分區&#xff09; [roo…

絕區陸--大語言模型的幻覺問題是如何推動科學創新

介紹 大型語言模型 (LLM)&#xff08;例如 GPT-4、LLaMA-2、PaLM-2、Claude-2 等&#xff09;已展示出為各種應用生成類似人類文本的出色能力。然而&#xff0c;LLM 的一個鮮為人知的方面是它們傾向于“產生幻覺”或生成不正確或沒有根據的事實陳述。我不認為這僅僅是一個限制…

快速排序算法Python實現

快速排序原理和步驟 快速排序是一種高效的排序算法&#xff0c;基于分治法&#xff08;Divide and Conquer&#xff09;來實現。其基本思想是通過一次排序將數組分成兩部分&#xff0c;其中一部分的所有元素都小于另一部分&#xff0c;然后遞歸地對這兩部分進行排序。以下是快…

前端構建工具(webpackvite)

這里寫目錄標題 構建工具webpack介紹配置文件簡介entryoutputloaderbabel插件開發服務器&#xff08;webpack-dev-server&#xff09;soureMap vite 構建工具 當我們習慣了在node中編寫代碼的方式后&#xff0c;在回到前端編寫html、css、js這些東西會感覺到各種的不便。比如:…

夏季戶外綜合征怎么預防

以下是一些預防夏季戶外綜合征的有效方法&#xff1a; 做好防曬措施&#xff1a; 涂抹高倍數的防曬霜&#xff0c;每隔 2 - 3 小時重新涂抹一次。比如選擇 SPF50、PA 的防曬霜。佩戴寬邊帽子、太陽鏡和遮陽傘&#xff0c;減少陽光直射面部和眼睛。像漁夫帽、大檐帽能有效遮擋陽…

12-阿里云單細胞處理-PBMC(by-jmzeng)

scRNA_10X/seurat-v2/sup-patient1-PBMC.Rmd at master jmzeng1314/scRNA_10X (github.com) s04-運行seurat流程處理一萬個單細胞轉錄組數據并自動化出報告_嗶哩嗶哩_bilibili #section 3已更新#「生信技能樹」單細胞公開課2021_嗶哩嗶哩_bilibili 上傳讀取數據 可以配置租…

模擬型題目

題目類型&#xff1a; 給定操作&#xff0c;允許操作任意次 思路收集&#xff1a; 1.暴力遍歷&#xff1a;如Problem - B - Codeforces 直接讓每一個不同的進行操作 2.歸納&#xff1a;根據模擬來發現規律

RTK_ROS_導航(4):ROS中空地圖的生成與加載

1. 地圖加載 構建空白 Map 如下,以下為python代碼,生成了output_image.pgm 文件 一般你在什么地方運行該代碼,這個文件就生成在什么地方 import numpy as np size = 100 # 單位:m resulition = 0.05 # 單位:mw = round(size / resulition) IMAGE_DATA = np.zeros((w

ChatGPT:Swagger 的疑問

ChatGPT&#xff1a;Swagger 的疑問 這段代碼是做什么的&#xff0c;為什么每個微服務的寫法都一樣 springdoc:api-docs:enabled: true # 1. 是否開啟 Swagger 接文檔的元數據path: /v3/api-docsswagger-ui:enabled: true # 2.1 是否開啟 Swagger 文檔的官方 UI 界面path: /sw…

音視頻解封裝demo:使用libmp4v2解封裝(demux)出mp4文件中的h264視頻數據和aac語音數據

1、README 前言 本demo是使用的mp4v2來將mp4文件解封裝得到h264、aac的&#xff0c;目前demo提供的.a靜態庫文件是在x86_64架構的Ubuntu16.04編譯得到的&#xff0c;如果想在其他環境下測試demo&#xff0c;可以自行編譯mp4v2并替換相應的庫文件&#xff08;libmp4v2.a&#…

HTTP 范圍Range請求

HTTP 的 Range 請求使客戶端能夠要求服務器僅向其回傳 HTTP 消息的一部分 HTTP 的 Range 請求頭是 HTTP/1.1 協議的一個特性。它允許客戶端請求僅傳輸資源的某個特定部分&#xff0c;而不是整個資源。 適用場景 支持隨機訪問的媒體播放器明確只需大型文件某部分的數據處理工具…

2022 RoboCom 世界機器人開發者大賽-高職組(國賽):智能管家

人上了年紀&#xff0c;記性就會變差&#xff0c;時常不得不翻箱倒柜找東西。智能照護中心現在請你做一個簡單的智能管家程序&#xff0c;把老人家里的東西逐一編號&#xff0c;放進若干個收納箱里。當然收納箱也是有編號的&#xff0c;你的程序要記錄下哪個東西放在哪個收納箱…

R包: phyloseq擴增子統計分析利器

介紹 phyloseq包對多類型數據的綜合軟件&#xff0c;并其對這些數據提供統計分析和可視化方法。 微生物數據分析的主要挑戰之一是如何整合不同類型的數據&#xff0c;從而對其進行生態學、遺傳學、系統發育學、多元統計、可視化和檢驗等分析。同時&#xff0c;由于同行之間需要…

QT學習日記一

創建QT文件步驟 這是創建之后widget.cpp和widget.h文件的具體代碼解釋&#xff0c;也是主要操作的文件&#xff0c;其中main.cpp不用操作&#xff0c;ui則是圖形化操作界面&#xff0c;綜合使用時&#xff0c;添加一個元件要注意重編名和編譯一下&#xff0c;才能在widget這類…

生產者消費者模型和線程同步問題

文章目錄 線程同步概念生產者消費者模型條件變量使用條件變量喚醒條件變量 阻塞隊列 線程同步概念 互斥能保證安全,但是僅有安全不夠,同步可以更高效的使用資源 生產者消費者模型 下面就基于生產者消費者來深入線程同步等概念: 如何理解生產消費者模型: 以函數調用為例: 兩…

[高頻 SQL 50 題(基礎版)]第一千七百五十七題,可回收且低脂產品

題目&#xff1a; 表&#xff1a;Products ---------------------- | Column Name | Type | ---------------------- | product_id | int | | low_fats | enum | | recyclable | enum | ---------------------- product_id 是該表的主鍵&#xff08;具有唯…

SQLite 命令行客戶端 + HTA 實現簡易UI

SQLite 命令行客戶端 HTA 實現簡易UI SQLite 客戶端.hta目錄結構參考資料 僅用于探索可行性&#xff0c;就只實現了 SELECT。 SQLite 客戶端.hta <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; cha…