您的位置:首页技术文章
文章详情页

如何使用Python实现一个简易的ORM模型

【字号: 日期:2022-06-19 18:44:35浏览:5作者:猪猪
目录元类描述器

本文记录下自己使用Python实现一个简易的ORM模型

使用到的知识

1、元类

2、描述器

元类

对于元类,我的理解其实也便较浅,大概是这个意思

所有的类都是使用元类来进行创建的,而所有的类的父类中必然是object(针对Python3),Python中的元类只有一个(type),当然这里不包含自定义元类

下面我们来看下类的创建

class Test: # 定义一个类 passTest1 = type('Test2',(object,),{'name':'test'}) # 定义一个类print(type(Test))print(type(Test1))-----------------------<class ’type’><class ’type’>

从上面可以看出创建类,其实是有两种方式,一种是通过class关键字来定义,一种是通过type来进行创建,当然常用的是使用class来进行创建了,在看最后的结果,可以看出类的类型为type。说明我们这个类就是由type来创建的

明白了这个之后我们再来梳理下怎么使用自定义元类来创建类,明白一点,自定义元类需要继承type

class MetaClass(type): # 定义一个元类 passclass Test(metaclass=MetaClass): # 使用自定义元类来创建类 passprint(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 = Noneclass 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: passclass 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 = Noneclass IntFiled(BaseFiled): '''定义一个数值的类型限制''' def __set__(self, instance, value):if isinstance(value, int): self.value = valueelse: raise TypeError('need a int') def __get__(self, instance, owner):return self.value def __delete__(self, instance):self.value = Noneclass BoolFiled(BaseFiled): '''定义一个布尔的类型限制''' def __set__(self, instance, value):if isinstance(value, bool): self.value = valueelse: 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_dictdic = {} # 定义一个空字典,用来装属性名和属性值for k, v in fileds.items(): value = getattr(self, k) dic[k] = valuesql = 'insert into {} values{}'.format(table_name, tuple(dic.values()))return sqlclass 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: passclass 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 = Noneclass IntFiled(BaseFiled): '''定义一个数值的类型限制''' def __set__(self, instance, value):if isinstance(value, int): self.value = valueelse: raise TypeError('need a int') def __get__(self, instance, owner):return self.value def __delete__(self, instance):self.value = Noneclass BoolFiled(BaseFiled): '''定义一个数值的类型限制''' def __set__(self, instance, value):if isinstance(value, bool): self.value = valueelse: raise TypeError('need a bool') def __get__(self, instance, owner):return self.value def __delete__(self, instance):self.value = Noneclass 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_dictdic = {} # 定义一个空字典,用来装属性名和属性值for k, v in fileds.items(): value = getattr(self, k) dic[k] = valuesql = 'insert into {} values{}'.format(table_name, tuple(dic.values()))return sqlclass 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 编程
相关文章: