python中通过元类(TYPE)简单实现对象关系映射(ORM)
Posted lzb888
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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形参背后真正替换的属性,所以用setattr def 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的父类:M
etaclass是类的模板,所以必须从`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__函数创建的对象。
以上是关于python中通过元类(TYPE)简单实现对象关系映射(ORM)的主要内容,如果未能解决你的问题,请参考以下文章
35.Python面向对象元类:type()__metaclass__属性实现简易ORM框架
35.Python面向对象元类:type()__metaclass__属性实现简易ORM框架