python中通过元类(TYPE)简单实现对象关系映射(ORM)

ORM是创建一个实例对象,用创建他的类名当做数据表名,用创建他的类属性对应数据表的字段,不需要在自己写复杂的sql语句,而是通过对实例对象的操作时,能让代码自动帮我们整理为对应的sql语句。

class User(父类):uid = ("uid", "int unsigned")name = ("username", "varchar(20)")password = ("password", "varchar(20)")...省略...

 

数据库
uid
username
password
   
   

 

类似下图创建一个实例对象,把数据库的数据以参数入

u = User(nid=12345, name="laowang",password="123321")

通过调用某个方法,ORM自动帮我们整理为下面代码并执行:

insert into (uid,name,password) value (12345,"laowang","123321")

从而大大简化我们的工作,减少出错率!下面是完整代码(通过metaclass可以指定我们需要继承的元类):

class Mode_type(type):def __new__(cls, name, bases, attrs)mappings = dict()for k, v in attrs.items():if isinstanse(v, tuple):mappings[k] = v# 找到新字典接收完attrs的数据后,删掉attrs里的数据for k in mappings.keys[]:attrs.pop(k)# 将之前新字典保存的数据表的信息保存在attrs中attrs["__mappings__"] = mappings# name指向新创建的实例对象名,相当于保存数据表的名称attrs["__table__"] = name    return type.__new__(cls, name, bases, attrs)class User(mateclass = Mode_type):uid = ("uid", "int unsigned")name = ("username", "varchar(20)")password = ("password", "varchar(20)")#  指定元类后,以上的类属性就不在类中,而是在__mapping__指定的字典中仓储# 类似于# __mapping__ = {#        uid :("uid", "int unsigned")#        name: ("username", "varchar(20)")#        password :("password", "varchar(20)")# }# __table__ = "User"def __init__(self, **kwargs):# 取出字典里面的值for name, value in kwargs.items():setattr(self, name, value)# 这里不能用self.name = value ,这样只会让实例对象拥有name这个属性,而不是name形参背后真正替换的属性,所以用setattrdef save()# 数据表表头字段fields = []# 数据表字段对应的数据args = []for k, v in self.__mappings__.items():field.append(v[0])args.append(getattr(self, k, None))args_temp = list()# 区分参数的类型,防止写入数据表后报错for temp in args:if isinstence(temp, int):args_temp.append(str(temp))  # 类似temp = “123456”elif isinstence(temp, str):args_temp.append("""%s""" % temp)  # 类似temp = """'123321'"""sql = "insert into %s (%s) value (%s)" % (self.__table__, ",".join(fields), ",".join(args_temp))#  下面就可以执行mysql的操作,只是说ORM,所以我只打印了这句话    print(sql)u = User(uid = 123456, name="laowang", password = "123321")
u.save()

需要注意的点:

  • Metaclass的父类:Metaclass是类的模板,所以必须从`type`类型继承:
  • 选择__new__函数作为实现"修改类"的函数
    • 函数__new__(cls, name,bases,attrs)中,"cls"类似于类中其他函数的self参数,例如__init__(self),只不过self代表创建的对象,而cls代表类本身(__init__作为实例初始化的函数,需要把实例本身作为参数传进去,这样我们才能保证被修改的是实例;同理,__new__函数需要把类本身作为参数传进去,才能保证被初始化的是当前类); name代表类的名称;bases代表当前类的父类集合;attrs代表当前类的属性,是狭义上属性和方法的集合,可以用字典dict的方式传入
    • 其实我们看下用type创建一个类就很好理解这些参数了():
      u = type('User', (object,),{uid:("uid", "int unsigned"),name :("username", "varchar(20)"),password:("password", "varchar(20)"})
    • 对__new__的定义def __new__(cls, name,bases,attrs),实际上,“new”方法在Python中是真正的构造方法(创建并返回实例),通过这个方法可以产生一个”cls”对应的实例对象所以说”new”方法一定要有返回,要把创建的实例对象返回回去。在此,我们把对类的修改放到__new__方法中,然后返回修改过后的实例对象。另外,很简单的道理,选择type.__new__函数作为return的值,是因为我们的Mode_type继承自type,因此应该返回type的__new__函数创建的对象。

转载于:https://www.cnblogs.com/lzb888/p/11145901.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263603.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ORA-12519: TNS:no appropriate service handler found 解决

selectcount(*) fromv$process --当前的连接数selectvalue fromv$parameter wherename processes--数据库允许的最大连接数修改最大连接数:altersystem setprocesses 300scope spfile;重启数据库:shutdownimmediate;startup;--查看当前有哪些用户正在使用数据SELECTosuser, a.u…

Linux下Web效力器架设攻略-1

来日诰日我们来看看怎样将Web效力器架在Linux零碎下。    LINUX零碎中罕见的有:CERN、NCSA、Apache三种体式格式,浅显最常用的要领就是用Apache。此种体式格式特点分明,设置装备部署简明,具有最大的对零碎兼容性,以…

Codeforces 1188A 构造

题意:给你一颗树,树的边权都是偶数,并且边权各不相同。你可以选择树的两个叶子结点,并且把两个叶子结点之间的路径加上一个值(可以为负数),问是否可以通过这种操作构造出这颗树?如果…

iOS- 关于AVAudioSession的使用——后台播放音乐

1.前言   •AVAudioSession是一个单例,无需实例化即可直接使用。AVAudioSession在各种音频环境中起着非常重要的作用•针对不同的音频应用场景,需要设置不同的音频会话分类1.1AVAudioSession的类别   •AVAudioSessionCategoryAmbient–混音播放&…

检索

【摘抄】基于线性表的检索一、检索的基本概念和算法分类1、检索概念: 可以形式化地定义基于关键码的检索。假定k1、k2…kn是互不相同的关键码值,有一个包含n条记录的集合C,形式如下: (k1, R1),(k2, R2),…

ajax请求后无法实现指定页面跳转或带参数跳转

问题:我们通过Ajax在前端对Controller的接口进行请求,处理完成后,无法通过Controller的return方法返回指定的页面。 原因:ajax只是局部刷新,所以不能在后台接口直接进行页面的跳转,我们可以在ajax的succes…

例说C#深拷贝与浅拷贝

一开始,先对C#深拷贝与浅拷贝知识做个简单的总结。 无论是浅拷贝与深拷贝,C#都将源对象中的所有字段复制到新的对象中。不过,对于值类型字段,引用类型字段以及字符串类型字段的处理,两种拷贝方式存在一定的区别&#x…

c++程序的多文件组织

当程序规模变大后,一个程序用多个文件组织,便于组织生产。这样,不必每次都重复对所有代码进行编译,而只需编译一次即可。把编译后所形成的目标文件保存起来,以后在需要时把它调出来直接与程序的目标文件相连接即可。 C…

strconv---用来基本类型之间的转换

strconv---用来基本类型之间的转换字符串转int:Atoi(s string)(i int,err error)int转字符串: Itoa(i int)stringstring转换为对应TP类型:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。因为string转其它类型可能会失败,所以这些函数…

企业架构 - 开篇:TOGAF介绍

在《年度总结和计划:去年4个1,今年5个1》中说过今年我准备在项目组引入一个架构方TOGAF。工业和信息化部副部长杨学山在一次内部座谈时提到:与西方发达国家比,国内的信息化建设在硬件方面已经不相上下,在软件方面有5年…

Linux操作系统定时任务系统 Cron

/sbin/service crond start //启动服务 /sbin/service crond stop //关闭服务 /sbin/service crond restart //重启服务 /sbin/service crond reload //重新载入配置 你也可以将这个服务在系统启动的时候自动启动: 在/etc/rc.d/rc.local这个脚本的末尾加上: /sbin/service cron…

C#(4) implicit explicit

最近几节课学的知识点的量有很大增长,加上上机和托福考试的临近,这里练习的所有代码就不走形式全贴出来了,找我自己觉得又不熟悉的点贴出来,争取简明扼要,恩恩 这次主要看接口的问题: 接口可以多继承&#…

什么是SNAT、DNAT?

什么是SNAT、DNAT?SNAT 企业内部的主机A想访问互联网上的主机C,首先将请求数据包(源:ipA,目标:ipC)发送到防火墙所在主机B,B收到后将数据包源地址改为本机公网网卡的ip(源…

ASP.NET读取(导入)CSV文件[献给菜鸟的我们]

CSV文件本身是TXT文件。 所以..可以通过FileStream文件流的方式读取. 如下代码: public void GetCSV1() { FileStream fs new FileStream("D:\\ReportLowIDAndHighID.csv", FileMode.Open, FileAccess.Read); //FileStream fs new FileStream(&…

【jquery】基于 jquery 实现 ie 浏览器兼容 placeholder 效果

placeholder 是 html5 新增加的属性,主要提供一种提示(hint),用于描述输入域所期待的值。该提示会在输入字段为空时显示,并会在字段获得焦点时消失。placeholder 属性适用于以下类型的 input 标签:text, se…

连接远程电脑中的虚拟机---端口映射

连接远程电脑中的虚拟机---端口映射问题:A主机中运行有2台虚拟机,现在我们希望在B主机中通过ssh(或其他方式)访问A主机中的2台虚拟机。(前提:B主机可以ping通A主机,即A有公网IP或A、B在同一子网下) 解决方法 设置虚拟…

Unity 动画属性

在动画的使用上使用不当的设置往往会造成不可预料的结果。 首先,如果动画自身可以驱动物体移动,那么在Animator组件上必须选择apply root motion,物体的动画位移才能生效,否则动画只能在原地播放。 第二,Bake Into Pos…

获取Dataset前几条数据的两种方法

第一种 public static DataView GetLatestComments(int numComments) { DataView Comments new DataView(GetComments()); Comments.Sort “DateCreated Desc“; string filter string.Empty; string delimiter string.Empty; numComments Math.Min(numComments, Comm…

Javascript正则匹配数字,中英文,中横线,下划线,utf-8中文

为什么80%的码农都做不了架构师?>>> function check_string(nickname) {var reg /^[A-Za-z0-9-_\u4e00-\u9fa5]{4,30}$/;if (!reg.test(nickname)) {return false;}return true; } 转载于:https://my.oschina.net/biezhi/blog/396989

解决<style>无法重写.css文件的问题

解决style无法重写.css文件的问题问题:在main.css已经定义了.main_content {width: 10px;}。然而现在在index.html中,我们希望main_content的宽度设置为20px。 解决思路:在index.html中加入如下定义后,我们会发现格式依旧为10px&…