本文记录下自己使用Python实现一个简易的ORM模型
使用到的知识
1、元类
2、描述器
元类
对于元类,我的理解其实也便较浅,大概是这个意思
所有的类都是使用元类来进行创建的,而所有的类的父类中必然是object(针对Python3),Python中的元类只有一个(type),当然这里不包含自定义元类
下面我们来看下类的创建
1
2
3
4
5
6
7
8
9
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class MetaClass( type ): # 定义一个元类
pass
class Test(metaclass = MetaClass): # 使用自定义元类来创建类
pass
print ( type (Test))
- - - - - - - - - - - - - - - - - - - - - - - - - -
< class '__main__.MetaClass' >
|
很明显可以看出Test类就是用MetaClass类创建出来的
描述器
从描述器的定义来说,只要一个类中实现了__get__、__set__、__delete__中的一个或几个,这个类的实例就可以叫描述器
下面我们来定义一个简易的描述器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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、利用元类实现映射关系
好,我们先利用描述器来实现对数据字段的类型,长度限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
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
|
上面实现了三种,分别是字符串、数值、布尔值的,下面在来实现元类以及模型类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
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。
下面贴一下完整的代码吧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# -*- 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模型的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/Pycainiao/p/14756759.html