如何使用Python实现一个简易的ORM模型
本文记录下自己使用Python实现一个简易的ORM模型
使用到的知识
1、元类
2、描述器
元类
对于元类,我的理解其实也便较浅,大概是这个意思
所有的类都是使用元类来进行创建的,而所有的类的父类中必然是object(针对Python3),Python中的元类只有一个(type),当然这里不包含自定义元类
下面我们来看下类的创建
class Test: # 定义一个类 pass Test1 = type("Test2",(object,),{"name":"test"}) # 定义一个类 print(type(Test)) print(type(Test1))----------------------- <class 'type'><class 'type'>
从上面可以看出创建类,其实是有两种方式,一种是通过class关键字来定义,一种是通过type来进行创建,当然常用的是使用class来进行创建了,在看最后的结果,可以看出类的类型为type。说明我们这个类就是由type来创建的
明白了这个之后我们再来梳理下怎么使用自定义元类来创建类,明白一点,自定义元类需要继承type
class MetaClass(type): # 定义一个元类 pass class Test(metaclass=MetaClass): # 使用自定义元类来创建类 pass print(type(Test)) -------------------------- <class '__main__.MetaClass'>
很明显可以看出Test类就是用MetaClass类创建出来的
描述器
从描述器的定义来说,只要一个类中实现了__get__、__set__、__delete__中的一个或几个,这个类的实例就可以叫描述器
下面我们来定义一个简易的描述器
class Describer: def __set__(self, instance, value): print("设置属性的时候会被调用") self.value = value def __get__(self, instance, owner): print("获取属性的时候会被调用") return self.value def __delete__(self, instance): print("删除属性的时候会被调用") self.value = None class Test: name = Describer() t = Test() t.name = "xxxxx" print(t.name) ---------------------- 设置属性的时候会被调用 获取属性的时候会被调用 xxxxx
从上面的代码中有没有什么想法?既然__set__方法会在我们设置属性的时候会被调用,那么我们是不是可以在设置属性前对这个属性做一些操作呢?
ORM模型
ORM模型到底是个啥?ORM对于后端研发来说肯定是不陌生的,包括很多后端框架现在都自带这个模型了
ORM(Object Relational Mapping)对象关系映射
既然是对象关系映射,那对象是啥?我的理解为:Python中的类与数据库之间的映射,对数据的操作就不用编写SQL语言了,因为都封装好了,比如你想插入一条数据,你就直接创建一个对象即可,
Python ------->>>> 数据库
类名 ------->>>> 数据库中的表名
对象 ------->>>> 数据库中的一行数据
属性 ------->>>> 数据库中的字段
大致就是上面的映射关系
ORM实现步骤
1、利用描述器实现对数据库字段的类型、长度限制
2、实现Mode类,也就是Python中的类
3、利用元类实现映射关系
好,我们先利用描述器来实现对数据字段的类型,长度限制
class BaseFiled: pass class CharFiled(BaseFiled): """定义一个字符串的类型限制""" def __init__(self, length=10): self.length = length def __set__(self, instance, value): if isinstance(value, str): if len(value) <= self.length: self.value = value else: raise ValueError("length can not exceed {}".format(self.length)) else: raise TypeError("need a str") def __get__(self, instance, owner): return self.value def __delete__(self, instance): self.value = None class IntFiled(BaseFiled): """定义一个数值的类型限制""" def __set__(self, instance, value): if isinstance(value, int): self.value = value else: raise TypeError("need a int") def __get__(self, instance, owner): return self.value def __delete__(self, instance): self.value = None class BoolFiled(BaseFiled): """定义一个布尔的类型限制""" def __set__(self, instance, value): if isinstance(value, bool): self.value = value else: raise TypeError("need a bool") def __get__(self, instance, owner): return self.value def __delete__(self, instance): self.value = None
上面实现了三种,分别是字符串、数值、布尔值的,下面在来实现元类以及模型类
class MyMateClass(type): """自定义一个元类""" def __new__(cls, name: str, bases: tuple, dic: dict, *args, **kwargs): """ :param name: name为模型类的类名也就是数据库中的表名 :param bases: bases为一个元祖类型,里面装的是name这个类的父类 :param dic: dic为一个dict类型,装的是name这个类中的属性 :param args: :param kwargs: :return: """ if name == "BaseMode": # 判断类名是否为BaseMode,如果是则直接使用元类创建类,不做其他任何操作 return super().__new__(cls, name, bases, dic) else: table_name = name.lower() # 将表名变成小写 filed_dic = {} # 定义一个空的列表,用来装dic中属于BaseFiled类型的属性,因为dic中会有其他创建类时自动生成的属性,这些属性我们没必要去建立映射关系,所以需要将其剔除掉 for k, v in dic.items(): if isinstance(v, BaseFiled): filed_dic[k] = v dic["t_name"] = table_name # 将表名添加到dic中,实现类名与表名的映射关系 dic["filed_dict"] = filed_dic # 将属于BaseFiled类型的属性给添加到dic中,实现属性与字段的映射关系 return super().__new__(cls, name, bases, dic) class BaseMode(metaclass=MyMateClass): def __init__(self, **kwargs): """ 由于每一个模型类(也就是数据库表)的属性个数不一致,所以我们需要定义一个父类来进行定义初始化的属性 :param kwargs: """ for k, v in kwargs.items(): # 遍历传进来的所有属性 setattr(self, k, v) # 拿到这些属性后对self(也就是类本身)进行设置属性 def save(self): """生成SQL语句""" # 获取表名 table_name = self.t_name # 获取所有的属性 fileds = self.filed_dict dic = {} # 定义一个空字典,用来装属性名和属性值 for k, v in fileds.items(): value = getattr(self, k) dic[k] = value sql = "insert into {} values{}".format(table_name, tuple(dic.values())) return sql class User(BaseMode): name = CharFiled() age = IntFiled() love = CharFiled(length=50) live = BoolFiled() if __name__ == '__main__': c = User(name="lc", age=12, love="hjh", live=True) c.save() -------------------------- insert into user values('lc', 12, 'hjh', True)
以上就实现了一个简单的ORM模型了,这个虽然在测试开发过程中用的很少(一般都是直接用框架中封装好的),学习这个也是为了更好的理解原理,后面好学习flask以及Django。
下面贴一下完整的代码吧
# -*- coding: utf-8 -*- # @Time : 2021-05-11 10:14 # @Author : cainiao # @File : Meat.py # @Software: PyCharm # @Content : 实现ORM模型 class BaseFiled: pass class CharFiled(BaseFiled): """定义一个字符串的类型限制""" def __init__(self, length=10): self.length = length def __set__(self, instance, value): if isinstance(value, str): if len(value) <= self.length: self.value = value else: raise ValueError("length can not exceed {}".format(self.length)) else: raise TypeError("need a str") def __get__(self, instance, owner): return self.value def __delete__(self, instance): self.value = None class IntFiled(BaseFiled): """定义一个数值的类型限制""" def __set__(self, instance, value): if isinstance(value, int): self.value = value else: raise TypeError("need a int") def __get__(self, instance, owner): return self.value def __delete__(self, instance): self.value = None class BoolFiled(BaseFiled): """定义一个数值的类型限制""" def __set__(self, instance, value): if isinstance(value, bool): self.value = value else: raise TypeError("need a bool") def __get__(self, instance, owner): return self.value def __delete__(self, instance): self.value = None class MyMateClass(type): """自定义一个元类""" def __new__(cls, name: str, bases: tuple, dic: dict, *args, **kwargs): """ :param name: name为模型类的类名也就是数据库中的表名 :param bases: bases为一个元祖类型,里面装的是name这个类的父类 :param dic: dic为一个dict类型,装的是name这个类中的属性 :param args: :param kwargs: :return: """ if name == "BaseMode": # 判断类名是否为BaseMode,如果是则直接使用元类创建类,不做其他任何操作 return super().__new__(cls, name, bases, dic) else: table_name = name.lower() # 将表名变成小写 filed_dic = {} # 定义一个空的列表,用来装dic中属于BaseFiled类型的属性,因为dic中会有其他创建类时自动生成的属性,这些属性我们没必要去建立映射关系,所以需要将其剔除掉 for k, v in dic.items(): if isinstance(v, BaseFiled): filed_dic[k] = v dic["t_name"] = table_name # 将表名添加到dic中,实现类名与表名的映射关系 dic["filed_dict"] = filed_dic # 将属于BaseFiled类型的属性给添加到dic中,实现属性与字段的映射关系 return super().__new__(cls, name, bases, dic) class BaseMode(metaclass=MyMateClass): def __init__(self, **kwargs): """ 由于每一个模型类(也就是数据库表)的属性个数不一致,所以我们需要定义一个父类来进行定义初始化的属性 :param kwargs: """ for k, v in kwargs.items(): # 遍历传进来的所有属性 setattr(self, k, v) # 拿到这些属性后对self(也就是类本身)进行设置属性 def save(self): """生成SQL语句""" # 获取表名 table_name = self.t_name # 获取所有的属性 fileds = self.filed_dict dic = {} # 定义一个空字典,用来装属性名和属性值 for k, v in fileds.items(): value = getattr(self, k) dic[k] = value sql = "insert into {} values{}".format(table_name, tuple(dic.values())) return sql class User(BaseMode): name = CharFiled() age = IntFiled() love = CharFiled(length=50) live = BoolFiled() if __name__ == '__main__': c = User(name="lc", age=12, love="hjh", live=True) print(c.save()) # c.name="lc" # print(c.name)
以上就是如何使用Python实现一个简易的ORM模型的详细内容,更多关于python 实现ORM模型的资料请关注猪先飞其它相关文章!
相关文章
- 这篇文章主要介绍了python-opencv-画外接矩形框的实例代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-04
Python astype(np.float)函数使用方法解析
这篇文章主要介绍了Python astype(np.float)函数使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-08- 2022虎年新年即将来临,小编为大家带来了一个利用Python编写的虎年烟花特效,堪称全网最绚烂,文中的示例代码简洁易懂,感兴趣的同学可以动手试一试...2022-02-14
- 在本篇文章里小编给大家分享的是一篇关于python中numpy.empty()函数实例讲解内容,对此有兴趣的朋友们可以学习下。...2021-02-06
python-for x in range的用法(注意要点、细节)
这篇文章主要介绍了python-for x in range的用法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-10- 这篇文章主要介绍了Python 图片转数组,二进制互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
- 这篇文章主要介绍了Python中的imread()函数用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-16
- 这篇文章主要介绍了python如何实现b站直播自动发送弹幕,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下...2021-02-20
python Matplotlib基础--如何添加文本和标注
这篇文章主要介绍了python Matplotlib基础--如何添加文本和标注,帮助大家更好的利用Matplotlib绘制图表,感兴趣的朋友可以了解下...2021-01-26- 这篇文章主要介绍了解决python 使用openpyxl读写大文件的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-13
- 今天小编就为大家分享一篇python 计算方位角实例(根据两点的坐标计算),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-27
- 本篇文章是对C#中WinForm控件之Dock顺序调整进行了详细的分析介绍,需要的朋友参考下...2020-06-25
- 这篇文章主要为大家详细介绍了python实现双色球随机选号,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-02
- 在本篇文章里小编给大家整理的是一篇关于python中使用np.delete()的实例方法,对此有兴趣的朋友们可以学习参考下。...2021-02-01
- 这篇文章主要介绍了使用Python的pencolor函数实现渐变色功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-09
- 这篇文章主要介绍了python自动化办公操作PPT的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-05
Python getsizeof()和getsize()区分详解
这篇文章主要介绍了Python getsizeof()和getsize()区分详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-20- 这篇文章主要介绍了WebStorm无法正确识别Vue3组合式API的解决方案,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...2021-02-18
- 这篇文章主要介绍了解决python 两个时间戳相减出现结果错误的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-12
- 这篇文章主要为大家详细介绍了python实现学生通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-25