博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python中通过元类(TYPE)简单实现对象关系映射(ORM)
阅读量:4307 次
发布时间:2019-06-06

本文共 3151 字,大约阅读时间需要 10 分钟。

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的父类: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

你可能感兴趣的文章
PHP empty、isset、innull的区别
查看>>
apache+nginx 实现动静分离
查看>>
通过Navicat远程连接MySQL配置
查看>>
phpstorm开发工具的设置用法
查看>>
Linux 系统挂载数据盘
查看>>
Git基础(三)--常见错误及解决方案
查看>>
Git(四) - 分支管理
查看>>
PHP Curl发送数据
查看>>
HTTP协议
查看>>
HTTPS
查看>>
git add . git add -u git add -A区别
查看>>
apache下虚拟域名配置
查看>>
session和cookie区别与联系
查看>>
PHP 实现笛卡尔积
查看>>
Laravel中的$loop
查看>>
CentOS7 重置root密码
查看>>
Centos安装Python3
查看>>
PHP批量插入
查看>>
laravel连接sql server 2008
查看>>
Laravel 操作redis的各种数据类型
查看>>