电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

用 Python 元類的特性實現 ORM 框架

瀏覽:3日期:2022-06-19 10:18:14
目錄ORM是什么實現ORM中的insert功能完善對數據類型的檢測抽取到基類中添加數據庫驅動執行sql語句添加數據庫驅動執行sql語句測試功能準備數據庫創建模型類測試源代碼ORM是什么

O是 object,也就 類對象 的意思,R是 relation,翻譯成中文是 關系,也就是關系數據庫中 數據表 的意思,M是 mapping,是映射的意思。在ORM框架中,它幫我們把類和數據表進行了一個映射,可以讓我們通過類和類對象就能操作它所對應的表格中的數據。ORM框架還有一個功能,它可以根據我們設計的類自動幫我們生成數據庫中的表,省去了我們自己建表的過程。

一個句話理解就是:創建一個實例對象,用創建它的類名當做數據表名,用創建它的類屬性對應數據表的字段,當對這個實例對象操作時,能夠對應 MySQL 語句。

在 Django 中就內嵌了一個 ORM 框架,不需要直接面向數據庫編程,而是定義模型類,通過模型類和對象完成數據表的增刪改查操作。還有第三方庫 sqlalchemy 都是 ORM框架。

用 Python 元類的特性實現 ORM 框架

先看看我們大致要實現什么功能

class User(父類省略): uid = (’uid’, 'int unsigned') name = (’username’, 'varchar(30)') email = (’email’, 'varchar(30)') password = (’password’, 'varchar(30)') ...省略...user = User(uid=123, name=’hui’, email=’huidbk@163.com’, password=’123456’)user.save()# 對應如下sql語句# insert into User (uid,username,email,password) values (123,hui,huidbk@163.com,123456)

所謂的 ORM 就是讓開發者在操作數據庫的時候,能夠像操作對象時通過xxxx.屬性=yyyy一樣簡單,這是開發ORM的初衷。

實現ORM中的insert功能

通過 Python 中 元類 簡單實現 ORM 中的 insert 功能

# !/usr/bin/python3# -*- coding: utf-8 -*-# @Author: Hui# @Desc: { 利用Python元類簡單實現ORM框架的Insert插入功能 }# @Date: 2021/05/17 17:02class ModelMetaclass(type): '''數據表模型元類''' def __new__(mcs, cls_name, bases, attrs):print(f’cls_name -> {cls_name}’) # 類名print(f’bases -> {bases}’) # 繼承類print(f’attrs -> {attrs}’) # 類中所有屬性print()# 數據表對應關系字典mappings = dict()# 過濾出對應數據表的字段屬性for k, v in attrs.items(): # 判斷是否是指定的StringField或者IntegerField的實例對象 # 這里就簡單判斷字段是元組 if isinstance(v, tuple):print(’Found mapping: %s ==> %s’ % (k, v))mappings[k] = v# 刪除這些已經在字典中存儲的字段屬性for k in mappings.keys(): attrs.pop(k)# 將之前的uid/name/email/password以及對應的對象引用、類名字# 用其他類屬性名稱保存attrs[’__mappings__’] = mappings # 保存屬性和列的映射關系attrs[’__table__’] = cls_name # 假設表名和類名一致return type.__new__(mcs, cls_name, bases, attrs)class User(metaclass=ModelMetaclass): '''用戶模型類'''# 類屬性名 表字段 表字段類型 uid = (’uid’, ’int unsigned’) name = (’username’, ’varchar(30)’) email = (’email’, ’varchar(30)’) password = (’password’, ’varchar(30)’) def __init__(self, **kwargs):for name, value in kwargs.items(): setattr(self, name, value) def save(self):fields = []args = []for k, v in self.__mappings__.items(): fields.append(v[0]) args.append(getattr(self, k, None))# 表名table_name = self.__table__# 數據表中的字段fields = ’,’.join(fields)# 待插入的數據args = ’,’.join([str(i) for i in args])# 生成sql語句sql = f'''insert into {table_name} ({fields}) values ({args})'''print(f’SQL: {sql}’)def main(): user = User(uid=123, name=’hui’, email=’huidbk@163.com’, password=’123456’) user.save()if __name__ == ’__main__’: main()

當 User 指定元類之后,uid、name、email、password 類屬性將不在類中,而是在 __mappings__ 屬性指定的字典中存儲。 User 類的這些屬性將轉變為如下

__mappings__ = { 'uid': (’uid’, 'int unsigned') 'name': (’username’, 'varchar(30)') 'email': (’email’, 'varchar(30)') 'password': (’password’, 'varchar(30)')}__table__ = 'User'

執行的效果如下:

cls_name -> Userbases -> ()attrs -> { ’__module__’: ’__main__’, ’__qualname__’: ’User’, ’__doc__’: ’用戶模型類’, ’uid’: (’uid’, ’int unsigned’), ’name’: (’username’, ’varchar(30)’), ’email’: (’email’, ’varchar(30)’), ’password’: (’password’, ’varchar(30)’), ’__init__’: <function User.__init__ at 0x0000026D520C1048>, ’save’: <function User.save at 0x0000026D520C10D8>}Found mapping: uid ==> (’uid’, ’int unsigned’)Found mapping: name ==> (’username’, ’varchar(30)’)Found mapping: email ==> (’email’, ’varchar(30)’)Found mapping: password ==> (’password’, ’varchar(30)’)SQL: insert into User (uid,username,email,password) values (123,hui,huidbk@163.com,123456)完善對數據類型的檢測

上面轉成的 sql 語句如下:

insert into User (uid,username,email,password) values (12345,hui,huidbk@163.com,123456)

發現沒有,在 sql 語句中字符串類型沒有沒有引號 ’’

正確的 sql 語句應該是:

insert into User (uid,username,email,password) values (123, ’hui’, ’huidbk@163.com’, ’123456’)

因此修改 User 類完善數據類型的檢測

class ModelMetaclass(type): # 此處和上文一樣, 故省略.... pass class User(metaclass=ModelMetaclass): '''用戶模型類''' uid = (’uid’, 'int unsigned') name = (’username’, 'varchar(30)') email = (’email’, 'varchar(30)') password = (’password’, 'varchar(30)') def __init__(self, **kwargs):for name, value in kwargs.items(): setattr(self, name, value) # 在這里完善數據類型檢測 def save(self):fields = []args = []for k, v in self.__mappings__.items(): fields.append(v[0]) args.append(getattr(self, k, None))# 把參數數據類型對應數據表的字段類型args_temp = list()for temp in args: if isinstance(temp, int):args_temp.append(str(temp)) elif isinstance(temp, str):args_temp.append(f'’{temp}’')# 表名table_name = self.__table__# 數據表中的字段fields = ’,’.join(fields)# 待插入的數據args = ’,’.join(args_temp)# 生成sql語句sql = f'''insert into {table_name} ({fields}) values ({args})'''print(f’SQL: {sql}’)def main(): user = User(uid=123, name=’hui’, email=’huidbk@163.com’, password=’123456’) user.save()if __name__ == ’__main__’: main()

運行效果如下:

cls_name -> Userbases -> ()attrs -> { ’__module__’: ’__main__’, ’__qualname__’: ’User’, ’__doc__’: ’用戶模型類’, ’uid’: (’uid’, ’int unsigned’), ’name’: (’username’, ’varchar(30)’), ’email’: (’email’, ’varchar(30)’), ’password’: (’password’, ’varchar(30)’), ’__init__’: <function User.__init__ at 0x0000026D520C1048>, ’save’: <function User.save at 0x0000026D520C10D8>}Found mapping: uid ==> (’uid’, ’int unsigned’)Found mapping: name ==> (’username’, ’varchar(30)’)Found mapping: email ==> (’email’, ’varchar(30)’)Found mapping: password ==> (’password’, ’varchar(30)’) SQL: insert into User (uid,username,email,password) values(123,’hui’,’huidbk@163.com’,’123456’)抽取到基類中

# !/usr/bin/python3# -*- coding: utf-8 -*-# @Author: Hui# @Desc: { 利用Python元類實現ORM框架的Insert插入功能 }# @Date: 2021/05/17 17:02class ModelMetaclass(type): '''數據表模型元類''' def __new__(mcs, cls_name, bases, attrs):print(f’cls_name -> {cls_name}’) # 類名print(f’bases -> {bases}’) # 繼承類print(f’attrs -> {attrs}’) # 類中所有屬性print()# 數據表對應關系字典mappings = dict()# 過濾出對應數據表的字段屬性for k, v in attrs.items(): # 判斷是否是對應數據表的字段屬性, 因為attrs中包含所有的類屬性 # 這里就簡單判斷字段是元組 if isinstance(v, tuple):print(’Found mapping: %s ==> %s’ % (k, v))mappings[k] = v# 刪除這些已經在字典中存儲的字段屬性for k in mappings.keys(): attrs.pop(k)# 將之前的uid/name/email/password以及對應的對象引用、類名字# 用其他類屬性名稱保存attrs[’__mappings__’] = mappings # 保存屬性和列的映射關系attrs[’__table__’] = cls_name # 假設表名和類名一致return type.__new__(mcs, cls_name, bases, attrs)class Model(object, metaclass=ModelMetaclass): '''數據表模型基類''' def __init__(self, **kwargs):for name, value in kwargs.items(): setattr(self, name, value) def save(self):fields = []args = []for k, v in self.__mappings__.items(): fields.append(v[0]) args.append(getattr(self, k, None))# 把參數數據類型對應數據表的字段類型args_temp = list()for temp in args: if isinstance(temp, int):args_temp.append(str(temp)) elif isinstance(temp, str):args_temp.append(f'’{temp}’')# 表名table_name = self.__table__# 數據表中的字段fields = ’,’.join(fields)# 待插入的數據args = ’,’.join(args_temp)# 生成sql語句sql = f'''insert into {table_name} ({fields}) values ({args})'''print(f’SQL: {sql}’)# 執行sql語句# ...class User(Model): '''用戶表模型類''' uid = (’uid’, 'int unsigned') name = (’username’, 'varchar(30)') email = (’email’, 'varchar(30)') password = (’password’, 'varchar(30)')def main(): user = User(uid=123, name=’hui’, email=’huidbk@163.com’, password=’123456’) user.save()if __name__ == ’__main__’: main()添加數據庫驅動執行sql語句

這里我們使用 pymysql 數據庫驅動,來執行 sql 語句

在 Model 類中新增一個 get_connection 的靜態方法用于獲取數據庫連接

import pymysqlclass Model(object, metaclass=ModelMetaclass): '''數據表模型基類''' def __init__(self, **kwargs):for name, value in kwargs.items(): setattr(self, name, value) @staticmethod def get_connection():'''獲取數據庫連接與數據游標:return: conn, cursor'''conn = pymysql.connect( database=’testdb’, host=’localhost’, port=3306, user=’root’, password=’123456’)return conn, conn.cursor() def save(self):fields = []args = []for k, v in self.__mappings__.items(): fields.append(v[0]) args.append(getattr(self, k, None))# 把參數數據類型對應數據表的字段類型args_temp = list()for temp in args: if isinstance(temp, int):args_temp.append(str(temp)) elif isinstance(temp, str):args_temp.append(f'’{temp}’')# 表名table_name = self.__table__# 數據表中的字段fields = ’,’.join(fields)# 待插入的數據args = ’,’.join(args_temp)# 生成sql語句sql = f'''insert into {table_name} ({fields}) values ({args})'''print(f’SQL: {sql}’)# 執行sql語句conn, cursor = self.get_connection()ret = cursor.execute(sql)print(ret)conn.commit()cursor.close()conn.close()添加數據庫驅動執行sql語句

這里我們使用 pymysql 數據庫驅動,來執行 sql 語句

在 Model 類中新增一個 get_connection 的靜態方法用于獲取數據庫連接

import pymysqlclass Model(object, metaclass=ModelMetaclass): '''數據表模型基類''' def __init__(self, **kwargs):for name, value in kwargs.items(): setattr(self, name, value) @staticmethod def get_connection():'''獲取數據庫連接與數據游標:return: conn, cursor'''conn = pymysql.connect( database=’testdb’, host=’localhost’, port=3306, user=’root’, password=’123456’)return conn, conn.cursor() def save(self):fields = []args = []for k, v in self.__mappings__.items(): fields.append(v[0]) args.append(getattr(self, k, None))# 把參數數據類型對應數據表的字段類型args_temp = list()for temp in args: if isinstance(temp, int):args_temp.append(str(temp)) elif isinstance(temp, str):args_temp.append(f'’{temp}’')# 表名table_name = self.__table__# 數據表中的字段fields = ’,’.join(fields)# 待插入的數據args = ’,’.join(args_temp)# 生成sql語句sql = f'''insert into {table_name} ({fields}) values ({args})'''print(f’SQL: {sql}’)# 執行sql語句conn, cursor = self.get_connection()ret = cursor.execute(sql)print(ret)conn.commit()cursor.close()conn.close()測試功能準備數據庫

先準備數據庫 testdb 和 user 數據表

create database testdb charset=utf8;use testdb;create table user(uid int unsigned auto_increment primary key,username varchar(30) not null,email varchar(30),password varchar(30) not null);

user 表結構如下

+----------+------------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+----------+------------------+------+-----+---------+----------------+| uid | int(10) unsigned | NO | PRI | NULL | auto_increment || username | varchar(30) | NO | | NULL ||| email | varchar(30) | YES | | NULL ||| password | varchar(30) | NO | | NULL ||+----------+------------------+------+-----+---------+----------------+創建模型類測試

class User(Model): '''用戶表模型類''' uid = (’uid’, 'int unsigned') name = (’username’, 'varchar(30)') email = (’email’, 'varchar(30)') password = (’password’, 'varchar(30)')def main(): user = User(uid=1, name=’hui’, email=’huidbk@163.com’, password=’123456’) user.save() for i in range(2, 10):user = User( uid=i, name=f’name{i}’, email=f’huidbk@16{i}.com’, password=f’12345{i}’)user.save() if __name__ == ’__main__’: main()

查看數據庫 user 表數據

mysql> select * from user;+-----+----------+----------------+----------+| uid | username | email | password |+-----+----------+----------------+----------+| 1 | hui | huidbk@163.com | 123456 || 2 | name2 | huidbk@162.com | 123452 || 3 | name3 | huidbk@163.com | 123453 || 4 | name4 | huidbk@164.com | 123454 || 5 | name5 | huidbk@165.com | 123455 || 6 | name6 | huidbk@166.com | 123456 || 7 | name7 | huidbk@167.com | 123457 || 8 | name8 | huidbk@168.com | 123458 || 9 | name9 | huidbk@169.com | 123459 |+-----+----------+----------------+----------+9 rows in set (0.00 sec)源代碼

源代碼已上傳到 Gitee PythonKnowledge: Python知識寶庫,歡迎大家來訪。

以上就是用 Python 元類的特性實現 ORM 框架的詳細內容,更多關于Python 實現 ORM 框架的資料請關注好吧啦網其它相關文章!

標簽: Python 編程
相關文章:
主站蜘蛛池模板: RV减速机-蜗轮蜗杆减速机-洗车机减速机-减速机厂家-艾思捷 | 杰恒蠕动泵-蠕动泵专业厂家-19年专注蠕动泵 | 挤出熔体泵_高温熔体泵_熔体出料泵_郑州海科熔体泵有限公司 | 冷水机-冰水机-冷冻机-冷风机-本森智能装备(深圳)有限公司 | 干粉砂浆设备_干混砂浆生产线_腻子粉加工设备_石膏抹灰砂浆生产成套设备厂家_干粉混合设备_砂子烘干机--郑州铭将机械设备有限公司 | 英思科GTD-3000EX(美国英思科气体检测仪MX4MX6)百科-北京嘉华众信科技有限公司 | 成都软件开发_OA|ERP|CRM|管理系统定制开发_成都码邻蜀科技 | 一级建造师培训_一建培训机构_中建云筑建造师培训网校 | PU树脂_水性聚氨酯树脂_聚氨酯固化剂_聚氨酯树脂厂家_宝景化工 | 网站优化公司_北京网站优化_抖音短视频代运营_抖音关键词seo优化排名-通则达网络 | 外观设计_设备外观设计_外观设计公司_产品外观设计_机械设备外观设计_东莞工业设计公司-意品深蓝 | 长江船运_国内海运_内贸船运_大件海运|运输_船舶运输价格_钢材船运_内河运输_风电甲板船_游艇运输_航运货代电话_上海交航船运 | 阻垢剂,反渗透阻垢剂,缓蚀阻垢剂-山东普尼奥水处理科技有限公司 真空粉体取样阀,电动楔式闸阀,电动针型阀-耐苛尔(上海)自动化仪表有限公司 | 重庆磨床过滤机,重庆纸带过滤机,机床伸缩钣金,重庆机床钣金护罩-重庆达鸿兴精密机械制造有限公司 | 金属抛光机-磁悬浮抛光机-磁力研磨机-磁力清洗机 - 苏州冠古科技 | CE认证_FCC认证_CCC认证_MFI认证_UN38.3认证-微测检测 CNAS实验室 | 冷却塔降噪隔音_冷却塔噪声治理_冷却塔噪音处理厂家-广东康明冷却塔降噪厂家 | 不锈钢/气体/液体玻璃转子流量计(防腐,选型,规格)-常州天晟热工仪表有限公司【官网】 | Safety light curtain|Belt Sway Switches|Pull Rope Switch|ultrasonic flaw detector-Shandong Zhuoxin Machinery Co., Ltd | 生物颗粒燃烧机-生物质燃烧机-热风炉-生物颗粒蒸汽发生器-丽水市久凯能源设备有限公司 | 青岛美佳乐清洁工程有限公司|青岛油烟管道清洗|酒店|企事业单位|学校工厂厨房|青岛油烟管道清洗 插针变压器-家用电器变压器-工业空调变压器-CD型电抗器-余姚市中驰电器有限公司 | 上海公众号开发-公众号代运营公司-做公众号的公司企业服务商-咏熠软件 | 青岛侦探_青岛侦探事务所_青岛劝退小三_青岛调查出轨取证公司_青岛婚外情取证-青岛探真调查事务所 | 高精度电阻回路测试仪-回路直流电阻测试仪-武汉特高压电力科技有限公司 | 天津试验仪器-电液伺服万能材料试验机,恒温恒湿标准养护箱,水泥恒应力压力试验机-天津鑫高伟业科技有限公司 | 天坛家具官网| 高低温万能试验机-复合材料万能试验机-馥勒仪器 | 氧氮氢联合测定仪-联测仪-氧氮氢元素分析仪-江苏品彦光电 | 长沙网站建设制作「网站优化推广」-网页设计公司-速马科技官网 | 小型UV打印机-UV平板打印机-大型uv打印机-UV打印机源头厂家 |松普集团 | 查分易-成绩发送平台官网| 国产离子色谱仪,红外分光测油仪,自动烟尘烟气测试仪-青岛埃仑通用科技有限公司 | 深圳品牌设计公司-LOGO设计公司-VI设计公司-未壳创意 | 散热器-电子散热器-型材散热器-电源散热片-镇江新区宏图电子散热片厂家 | 高压无油空压机_无油水润滑空压机_水润滑无油螺杆空压机_无油空压机厂家-科普柯超滤(广东)节能科技有限公司 | 青州搬家公司电话_青州搬家公司哪家好「鸿喜」青州搬家 | 热处理温控箱,热处理控制箱厂家-吴江市兴达电热设备厂 | 派克防爆伺服电机品牌|国产防爆伺服电机|高低温伺服电机|杭州摩森机电科技有限公司 | 圆盘鞋底注塑机_连帮鞋底成型注塑机-温州天钢机械有限公司 | 河南15年专业网站建设制作设计,做网站就找郑州启凡网络公司 | 实体店商新零售|微赢|波后|波后合作|微赢集团 |