激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語(yǔ)言編程技術(shù)及教程分享平臺(tái)!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Python - python利用元類和描述器實(shí)現(xiàn)ORM模型的詳細(xì)步驟

python利用元類和描述器實(shí)現(xiàn)ORM模型的詳細(xì)步驟

2022-03-07 00:25馬兒不會(huì)跑 Python

Python中的類與數(shù)據(jù)庫(kù)之間的映射,對(duì)數(shù)據(jù)的操作就不用編寫SQL語(yǔ)言了,因?yàn)槎挤庋b好了,比如你想插入一條數(shù)據(jù),你就直接創(chuàng)建一個(gè)對(duì)象即可,下面通過(guò)本文學(xué)習(xí)下python利用元類和描述器實(shí)現(xiàn)ORM模型的詳細(xì)步驟,感興趣的朋友一起

ORM模型

ORM模型對(duì)于后端開(kāi)發(fā)來(lái)說(shuō)肯定是不陌生的,包括很多后端框架比如django,現(xiàn)在都自帶這個(gè)模型了
ORM(Object Relational Mapping)對(duì)象關(guān)系映射
Python中的類與數(shù)據(jù)庫(kù)之間的映射,對(duì)數(shù)據(jù)的操作就不用編寫SQL語(yǔ)言了,因?yàn)槎挤庋b好了,比如你想插入一條數(shù)據(jù),你就直接創(chuàng)建一個(gè)對(duì)象即可,

類名 ------->>>> 數(shù)據(jù)庫(kù)中的表名

屬性 ------->>>> 數(shù)據(jù)庫(kù)中的字段

對(duì)象 ------->>>> 數(shù)據(jù)庫(kù)中的一行數(shù)據(jù)

大致就是上面的映射關(guān)系

ORM實(shí)現(xiàn)步驟:

1、利用描述器實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)字段的類型、長(zhǎng)度限制
2、實(shí)現(xiàn)模型類,也就是創(chuàng)建一張表并定義字段
3、利用元類實(shí)現(xiàn)映射關(guān)系

元類:

1.實(shí)例對(duì)象是通過(guò)類來(lái)創(chuàng)建,那類又是通過(guò)什么創(chuàng)建的呢?python中所有的類都是通過(guò)元類來(lái)創(chuàng)建類,且這個(gè)元類只有一個(gè)那就是type;

?
1
2
3
4
5
6
7
8
9
class Test:
    pass
 
t = Test()
print(type(Test))  #類是通過(guò)元類type創(chuàng)建
print(type(t))  #實(shí)例對(duì)象是通過(guò)類創(chuàng)建
#輸出-----------------------
<class 'type'>
<class '__main__.Test'>

2.除了通過(guò)class關(guān)鍵字創(chuàng)建類,我們也可以通過(guò)元類type來(lái)創(chuàng)建類,type作為python的內(nèi)置函數(shù),其實(shí)他也是一個(gè)類,他有兩個(gè)作用:
1.傳入一個(gè)變量,返回這個(gè)變量的類型;
2.創(chuàng)建類時(shí),第一個(gè)參數(shù)傳入類名,第二個(gè)參數(shù)傳入一個(gè)元祖,指定父類,第三個(gè)參數(shù)傳入字典設(shè)置類的屬性或方法;

?
1
2
3
4
5
6
7
8
9
#通過(guò)元類來(lái)創(chuàng)建類
test1 = type("test2",(object,),{"name":"xiaoming"})
t1 = test1()
 
print(type(test1))
print(type(t1))
#輸出---------------
<class 'type'>
<class '__main__.test2'>

自定義元類:

1.自定義一個(gè)元類,這個(gè)元類必須繼承type,用這個(gè)元類創(chuàng)建類時(shí),必須使用metaclass指定他的元類;

?
1
2
3
4
5
6
7
8
9
10
11
class MetaClass(type):
    """自定義一個(gè)元類,這個(gè)元類必須繼承type,用這個(gè)元類創(chuàng)建類時(shí),必須使用metaclass指定他的元類"""
    def __new__(cls, name, bases, dic, *args, **kwargs):
        return super().__new__(cls, name, bases, dic)
 
class Test(metaclass = MetaClass):
    name = "xiaoming"
 
print(type(Test))
#輸出----------------
<class '__main__.MetaClass'#可以看到此時(shí)這個(gè)類創(chuàng)建是用我們自定義的元類創(chuàng)建的,而不是type創(chuàng)建的

描述器:

1.描述器的定義,只要一個(gè)類中實(shí)現(xiàn)了__get__、set、__delete__中的一個(gè)或幾個(gè),這個(gè)類的實(shí)例就可以叫描述器,那描述器有神么作用呢,在我們給描述器設(shè)置屬性時(shí),一定會(huì)調(diào)用描述器里面的—set—方法,那我們?cè)谠O(shè)置屬性之前是不是可以在set方法里面,做一些手腳,比如校驗(yàn)這個(gè)屬性長(zhǎng)度,類型等等,如果不符合要求那就拋錯(cuò),如果符合那就設(shè)置成功;

?
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
class Describer:
"""
這是一個(gè)描述器,描述器一般不直接實(shí)例化對(duì)象,而是在另一個(gè)類里,給他設(shè)置屬性
"""
 
    def __set__(self, instance, value):
        print("設(shè)置屬性的時(shí)候會(huì)被調(diào)用")
        self.value = value
 
    def __get__(self, instance, owner):
        print("獲取屬性的時(shí)候會(huì)被調(diào)用")
        return self.value
 
    def __delete__(self, instance):
        print("刪除屬性的時(shí)候會(huì)被調(diào)用")
        self.value = None
 
 
class Test:
    name = Describer()
 
t = Test()
t.name = "xiaoming"  #給描述器設(shè)置一個(gè)類屬性
print(t.name)  #獲取一個(gè)類屬性
#輸出---------------
設(shè)置屬性的時(shí)候會(huì)被調(diào)用
獲取屬性的時(shí)候會(huì)被調(diào)用
xiaoming

利用描述器實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)字段的類型、長(zhǎng)度限制

設(shè)置屬性一定會(huì)調(diào)用描述器里面的—set—方法,再設(shè)置屬性之前校驗(yàn)這個(gè)屬性長(zhǎng)度,類型等等,如果不符合要求那就拋錯(cuò),如果符合那就設(shè)置成功;

?
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
class BaseFiled:#為什么要先定義一個(gè)父類呢,一會(huì)我們改造元類的時(shí)候會(huì)用到
    pass
 
 
class CharFiled(BaseFiled):
    """定義一個(gè)字符串的類型限制"""
 
    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):
    """定義一個(gè)數(shù)值的類型限制"""
 
    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

實(shí)現(xiàn)模型類,也就是創(chuàng)建一張表并定義字段:

模型類,這些字段是通過(guò)描述器來(lái)進(jìn)行長(zhǎng)度和類型校驗(yàn)的

?
1
2
3
4
5
class User():
"""這是一個(gè)模型類,相當(dāng)于定義了一個(gè)表名是User的表,表有三個(gè)字段name,age,love"""
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)

如果是這樣的話我們給這個(gè)類實(shí)例化的時(shí)候,需要這樣傳值:

?
1
2
3
4
t1 = User()
t1.name = "xiaoming"
t1.age = 18
t1.love = "single"

如果我們需要一次性傳入三個(gè)值得話,那就需要一個(gè)__init__來(lái)接收,但是模型類一般里面不定義init,所以我們可以給他找個(gè)父類,然后讓他繼承父類的init,這樣我們就可以一次傳入多個(gè)值,并且參數(shù)個(gè)數(shù)也不限定,優(yōu)化如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class BaseMode():
 
    def __init__(self, **kwargs):
        """
        由于每一個(gè)模型類(也就是數(shù)據(jù)庫(kù)表)的屬性個(gè)數(shù)不一致,所以我們需要定義一個(gè)父類來(lái)進(jìn)行定義初始化的屬性
        :param kwargs:
        """
        for k, v in kwargs.items():   # 遍歷傳進(jìn)來(lái)的所有屬性
            setattr(self, k, v)   # 拿到這些屬性后對(duì)self(也就是類本身)進(jìn)行設(shè)置屬性
 
class User(BaseMode):
"""第一個(gè)模型類"""
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)
 
t1 = User(name= "xiaoming",age=18,love="xxx")#現(xiàn)在我們就可以一次傳入多個(gè)值,并且參數(shù)個(gè)數(shù)也不限定
 
class Oder(BaseMode):
    """第二個(gè)模型類"""
    id = CharFiled()
    count = IntFiled()
    
t2 = Oder(id ="a1",count = 123)

利用元類實(shí)現(xiàn)模型類和數(shù)據(jù)庫(kù)映射關(guān)系:

其實(shí)就是創(chuàng)建模型類的時(shí)候,提取模型類的類名作為表名,提取模型類的屬性作為字段名,存儲(chǔ)在模型類的類屬性里,然后備用,代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MetaClass(type):
    """自定義一個(gè)元類,這個(gè)元類必須繼承type,用這個(gè)元類創(chuàng)建類時(shí),必須使用meteclass指定他的元類"""
    def __new__(cls, name, bases, dic, *args, **kwargs):
        if name == "BaseMode":   # (User,Oder,BaserMode都指定了用這個(gè)元類)我們的目的是對(duì)模型類(User,Oder)進(jìn)行提取操作,不對(duì)BaserMode進(jìn)行操作,所以先判斷類名是否為BaseMode,如果是則直接使用元類創(chuàng)建類,不需要提取
            return super().__new__(cls, name, bases, dic)
        else:
            table_name = name.lower()  # 提取表名,即模型類的類名,將表名變成小寫
            filed_dic = {}   # 定義一個(gè)空的列表,用來(lái)裝dic中(dic中的屬性就是模型類里面我們寫的字段)屬于BaseFiled類型的屬性,因?yàn)閐ic中會(huì)有其他創(chuàng)建類時(shí)自動(dòng)生成的屬性(例如__開(kāi)頭的一些),這些屬性我們沒(méi)必要去建立映射關(guān)系,所以需要將其剔除掉
            for k, v in dic.items():
                if isinstance(v,BaseFiled):
                    filed_dic[k] = v
            dic["t_name"] = table_name    # 給dic新加一個(gè)t_name的屬性,將表名添加到dic中,實(shí)現(xiàn)類名與表名的映射關(guān)系
            dic["filed_dict"] = filed_dic  # 給dic新加一個(gè)filed_dict的屬性,將屬于BaseFiled類型的屬性給添加到dic中,實(shí)現(xiàn)屬性與字段的映射關(guān)系
        return super().__new__(cls, name, bases,dic)

**創(chuàng)建模型類的時(shí)候,利用給他指定元類,提取了表名和字段名,我們具體要怎么用呢?**我們可以在模型類的父類里面定義一個(gè)save方法,然后用這些字段寫sql,在我們創(chuàng)建模型類的實(shí)例后,就調(diào)用這個(gè)save方法,即可向數(shù)據(jù)庫(kù)插入一條數(shù)據(jù)了,如下:

?
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
class BaseMode(metaclass=MetaClass):
 
    def __init__(self, **kwargs):
        """
        由于每一個(gè)模型類(也就是數(shù)據(jù)庫(kù)表)的屬性個(gè)數(shù)不一致,所以我們需要定義一個(gè)父類來(lái)進(jìn)行定義初始化的屬性
        :param kwargs:
        """
        for k, v in kwargs.items():   # 遍歷傳進(jìn)來(lái)的所有屬性
            setattr(self, k, v)   # 拿到這些屬性后對(duì)self(也就是類本身)進(jìn)行設(shè)置屬性
 
    def save(self):
        """生成SQL語(yǔ)句"""
        # 獲取表名
        table_name = self.t_name
        # 獲取所有的屬性
        fileds = self.filed_dict
        dic = {}  # 定義一個(gè)空字典,用來(lái)裝屬性名和屬性值
        for k, v in fileds.items():
            value = getattr(self, k)
            dic[k] = value
        sql = "insert into {} values{}".format(table_name, tuple(dic.values()))
        print(sql)
        return sql
 
class User(BaseMode):
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)
 
 
class Oder(BaseMode):
    """第二個(gè)模型類"""
    id = CharFiled()
    count = IntFiled()
 
t2 = Oder(id ="a1",count = 123)#實(shí)例化模型類,并調(diào)用save方法,即可向數(shù)據(jù)庫(kù)插入數(shù)據(jù)
t2.save()
 
t1 = User(name= "xiaoming",age=18,love="xxx")
t1.save()
#輸出-----------------------
insert into oder values('a1', 123)
insert into user values('xiaoming', 18, 'xxx')

至此我們的一個(gè)簡(jiǎn)單的ORM模型就定義好了,我們只需要理解原理即可,因?yàn)橐粋€(gè)成熟的后端框架都有現(xiàn)成的ORM模型,例如django和flask都自帶的有,最后再附上全部代碼,如果有幫到你,能點(diǎn)個(gè)贊嗎,謝謝咯~~~

?
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
class MetaClass(type):
    """自定義一個(gè)元類,這個(gè)元類必須繼承type,用這個(gè)元類創(chuàng)建類時(shí),必須使用meteclass指定他的元類"""
    def __new__(cls, name, bases, dic, *args, **kwargs):
        if name == "BaseMode":   # (User,Oder,BaserMode都指定了用這個(gè)元類)我們的目的是對(duì)模型類(User,Oder)進(jìn)行提取操作,不對(duì)BaserMode進(jìn)行操作,所以先判斷類名是否為BaseMode,如果是則直接使用元類創(chuàng)建類,不需要提取
            return super().__new__(cls, name, bases, dic)
        else:
            table_name = name.lower()  # 提取表名,即模型類的類名,將表名變成小寫
            filed_dic = {}   # 定義一個(gè)空的列表,用來(lái)裝dic中(dic中的屬性就是模型類里面我們寫的字段)屬于BaseFiled類型的屬性,因?yàn)閐ic中會(huì)有其他創(chuàng)建類時(shí)自動(dòng)生成的屬性(例如__開(kāi)頭的一些),這些屬性我們沒(méi)必要去建立映射關(guān)系,所以需要將其剔除掉
            for k, v in dic.items():
                if isinstance(v,BaseFiled):
                    filed_dic[k] = v
            dic["t_name"] = table_name    # 給dic新加一個(gè)t_name的屬性,將表名添加到dic中,實(shí)現(xiàn)類名與表名的映射關(guān)系
            dic["filed_dict"] = filed_dic  # 給dic新加一個(gè)filed_dict的屬性,將屬于BaseFiled類型的屬性給添加到dic中,實(shí)現(xiàn)屬性與字段的映射關(guān)系
        return super().__new__(cls, name, bases,dic)
 
 
class BaseFiled:
    pass
 
 
class CharFiled(BaseFiled):
    """定義一個(gè)字符串的類型限制"""
 
    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):
    """定義一個(gè)數(shù)值的類型限制"""
 
    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 BaseMode(metaclass=MetaClass):
 
    def __init__(self, **kwargs):
        """
        由于每一個(gè)模型類(也就是數(shù)據(jù)庫(kù)表)的屬性個(gè)數(shù)不一致,所以我們需要定義一個(gè)父類來(lái)進(jìn)行定義初始化的屬性
        :param kwargs:
        """
        for k, v in kwargs.items():   # 遍歷傳進(jìn)來(lái)的所有屬性
            setattr(self, k, v)   # 拿到這些屬性后對(duì)self(也就是類本身)進(jìn)行設(shè)置屬性
 
    def save(self):
        """生成SQL語(yǔ)句"""
        # 獲取表名
        table_name = self.t_name
        # 獲取所有的屬性
        fileds = self.filed_dict
        dic = {}  # 定義一個(gè)空字典,用來(lái)裝屬性名和屬性值
        for k, v in fileds.items():
            value = getattr(self, k)
            dic[k] = value
        sql = "insert into {} values{}".format(table_name, tuple(dic.values()))
        print(sql)
        return sql
 
class User(BaseMode):
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)
 
 
class Oder(BaseMode):
    """第二個(gè)模型類"""
    id = CharFiled()
    count = IntFiled()
 
t2 = Oder(id ="a1",count = 123)
t2.save()
 
t1 = User(name= "xiaoming",age=18,love="xxx")
t1.save()

到此這篇關(guān)于python利用元類和描述器實(shí)現(xiàn)ORM模型的文章就介紹到這了,更多相關(guān)python ORM模型內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://blog.csdn.net/weixin_48636525/article/details/121474590

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产亚洲网 | 色屁屁xxxxⅹ在线视频 | 国产色片在线观看 | 在线看免电影网站 | 成人毛片一区 | 99视频在线观看视频 | 成人一区二区在线观看视频 | 欧美特黄一级高清免费的香蕉 | 日本一区二区免费在线观看 | 欧美女同hd | 黄色毛片一级 | 午夜精品影院 | 性色吧| 国产精品啪一品二区三区粉嫩 | 国产精品视频亚洲 | 九九视频精品在线 | 亚洲精品欧美 | 欧美精品成人一区二区在线观看 | 9999久久久久久 | 91真视频 | av成人免费观看 | 欧美日本日韩 | 黄色毛片前黄 | 中日韩乱码一二新区 | 91a在线观看 | 999久久久国产999久久久 | 在线播放91 | 日韩电影av在线 | 99久久一区二区 | 国产一区日韩一区 | 国产正在播放 | 全黄毛片 | av在线免费网 | 欧美成人精品一级 | 国产第一页精品 | 欧美国产日韩在线 | 国产精品久久久久久久四虎电影 | 精品在线免费播放 | 亚洲国产馆| 在线播放免费人成毛片乱码 | 久久影院午夜 |