您好,登錄后才能下訂單哦!
本篇文章為大家展示了使用Python怎么實(shí)現(xiàn)一個(gè)ORM模型,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
對(duì)于元類(lèi),我的理解其實(shí)也便較淺,大概是這個(gè)意思
所有的類(lèi)都是使用元類(lèi)來(lái)進(jìn)行創(chuàng)建的,而所有的類(lèi)的父類(lèi)中必然是object(針對(duì)Python3),Python中的元類(lèi)只有一個(gè)(type),當(dāng)然這里不包含自定義元類(lèi)
下面我們來(lái)看下類(lèi)的創(chuàng)建
class Test: # 定義一個(gè)類(lèi) pass Test1 = type("Test2",(object,),{"name":"test"}) # 定義一個(gè)類(lèi) print(type(Test)) print(type(Test1))----------------------- <class 'type'><class 'type'>
從上面可以看出創(chuàng)建類(lèi),其實(shí)是有兩種方式,一種是通過(guò)class關(guān)鍵字來(lái)定義,一種是通過(guò)type來(lái)進(jìn)行創(chuàng)建,當(dāng)然常用的是使用class來(lái)進(jìn)行創(chuàng)建了,在看最后的結(jié)果,可以看出類(lèi)的類(lèi)型為type。說(shuō)明我們這個(gè)類(lèi)就是由type來(lái)創(chuàng)建的
明白了這個(gè)之后我們?cè)賮?lái)梳理下怎么使用自定義元類(lèi)來(lái)創(chuàng)建類(lèi),明白一點(diǎn),自定義元類(lèi)需要繼承type
class MetaClass(type): # 定義一個(gè)元類(lèi) pass class Test(metaclass=MetaClass): # 使用自定義元類(lèi)來(lái)創(chuàng)建類(lèi) pass print(type(Test)) -------------------------- <class '__main__.MetaClass'>
很明顯可以看出Test類(lèi)就是用MetaClass類(lèi)創(chuàng)建出來(lái)的
從描述器的定義來(lái)說(shuō),只要一個(gè)類(lèi)中實(shí)現(xiàn)了__get__、__set__、__delete__中的一個(gè)或幾個(gè),這個(gè)類(lèi)的實(shí)例就可以叫描述器
下面我們來(lái)定義一個(gè)簡(jiǎn)易的描述器
class Describer: 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 = "xxxxx" print(t.name) ---------------------- 設(shè)置屬性的時(shí)候會(huì)被調(diào)用 獲取屬性的時(shí)候會(huì)被調(diào)用 xxxxx
從上面的代碼中有沒(méi)有什么想法?既然__set__方法會(huì)在我們?cè)O(shè)置屬性的時(shí)候會(huì)被調(diào)用,那么我們是不是可以在設(shè)置屬性前對(duì)這個(gè)屬性做一些操作呢?
ORM模型
ORM模型到底是個(gè)啥?ORM對(duì)于后端研發(fā)來(lái)說(shuō)肯定是不陌生的,包括很多后端框架現(xiàn)在都自帶這個(gè)模型了
ORM(Object Relational Mapping)對(duì)象關(guān)系映射
既然是對(duì)象關(guān)系映射,那對(duì)象是啥?我的理解為:Python中的類(lèi)與數(shù)據(jù)庫(kù)之間的映射,對(duì)數(shù)據(jù)的操作就不用編寫(xiě)SQL語(yǔ)言了,因?yàn)槎挤庋b好了,比如你想插入一條數(shù)據(jù),你就直接創(chuàng)建一個(gè)對(duì)象即可,
Python ------->>>> 數(shù)據(jù)庫(kù)
類(lèi)名 ------->>>> 數(shù)據(jù)庫(kù)中的表名
對(duì)象 ------->>>> 數(shù)據(jù)庫(kù)中的一行數(shù)據(jù)
屬性 ------->>>> 數(shù)據(jù)庫(kù)中的字段
大致就是上面的映射關(guān)系
ORM實(shí)現(xiàn)步驟
1、利用描述器實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)字段的類(lèi)型、長(zhǎng)度限制
2、實(shí)現(xiàn)Mode類(lèi),也就是Python中的類(lèi)
3、利用元類(lèi)實(shí)現(xiàn)映射關(guān)系
好,我們先利用描述器來(lái)實(shí)現(xiàn)對(duì)數(shù)據(jù)字段的類(lèi)型,長(zhǎng)度限制
class BaseFiled: pass class CharFiled(BaseFiled): """定義一個(gè)字符串的類(lèi)型限制""" 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ù)值的類(lèi)型限制""" 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): """定義一個(gè)布爾的類(lèi)型限制""" 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
上面實(shí)現(xiàn)了三種,分別是字符串、數(shù)值、布爾值的,下面在來(lái)實(shí)現(xiàn)元類(lèi)以及模型類(lèi)
class MyMateClass(type): """自定義一個(gè)元類(lèi)""" def __new__(cls, name: str, bases: tuple, dic: dict, *args, **kwargs): """ :param name: name為模型類(lèi)的類(lèi)名也就是數(shù)據(jù)庫(kù)中的表名 :param bases: bases為一個(gè)元祖類(lèi)型,里面裝的是name這個(gè)類(lèi)的父類(lèi) :param dic: dic為一個(gè)dict類(lèi)型,裝的是name這個(gè)類(lèi)中的屬性 :param args: :param kwargs: :return: """ if name == "BaseMode": # 判斷類(lèi)名是否為BaseMode,如果是則直接使用元類(lèi)創(chuàng)建類(lèi),不做其他任何操作 return super().__new__(cls, name, bases, dic) else: table_name = name.lower() # 將表名變成小寫(xiě) filed_dic = {} # 定義一個(gè)空的列表,用來(lái)裝dic中屬于BaseFiled類(lèi)型的屬性,因?yàn)閐ic中會(huì)有其他創(chuàng)建類(lèi)時(shí)自動(dòng)生成的屬性,這些屬性我們沒(méi)必要去建立映射關(guān)系,所以需要將其剔除掉 for k, v in dic.items(): if isinstance(v, BaseFiled): filed_dic[k] = v dic["t_name"] = table_name # 將表名添加到dic中,實(shí)現(xiàn)類(lèi)名與表名的映射關(guān)系 dic["filed_dict"] = filed_dic # 將屬于BaseFiled類(lèi)型的屬性給添加到dic中,實(shí)現(xiàn)屬性與字段的映射關(guān)系 return super().__new__(cls, name, bases, dic) class BaseMode(metaclass=MyMateClass): def __init__(self, **kwargs): """ 由于每一個(gè)模型類(lèi)(也就是數(shù)據(jù)庫(kù)表)的屬性個(gè)數(shù)不一致,所以我們需要定義一個(gè)父類(lèi)來(lái)進(jìn)行定義初始化的屬性 :param kwargs: """ for k, v in kwargs.items(): # 遍歷傳進(jìn)來(lái)的所有屬性 setattr(self, k, v) # 拿到這些屬性后對(duì)self(也就是類(lèi)本身)進(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())) 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)
以上就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的ORM模型了,這個(gè)雖然在測(cè)試開(kāi)發(fā)過(guò)程中用的很少(一般都是直接用框架中封裝好的),學(xué)習(xí)這個(gè)也是為了更好的理解原理,后面好學(xué)習(xí)flask以及Django。
下面貼一下完整的代碼吧
# -*- coding: utf-8 -*- # @Time : 2021-05-11 10:14 # @Author : cainiao # @File : Meat.py # @Software: PyCharm # @Content : 實(shí)現(xiàn)ORM模型 class BaseFiled: pass class CharFiled(BaseFiled): """定義一個(gè)字符串的類(lèi)型限制""" 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ù)值的類(lèi)型限制""" 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): """定義一個(gè)數(shù)值的類(lèi)型限制""" 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): """自定義一個(gè)元類(lèi)""" def __new__(cls, name: str, bases: tuple, dic: dict, *args, **kwargs): """ :param name: name為模型類(lèi)的類(lèi)名也就是數(shù)據(jù)庫(kù)中的表名 :param bases: bases為一個(gè)元祖類(lèi)型,里面裝的是name這個(gè)類(lèi)的父類(lèi) :param dic: dic為一個(gè)dict類(lèi)型,裝的是name這個(gè)類(lèi)中的屬性 :param args: :param kwargs: :return: """ if name == "BaseMode": # 判斷類(lèi)名是否為BaseMode,如果是則直接使用元類(lèi)創(chuàng)建類(lèi),不做其他任何操作 return super().__new__(cls, name, bases, dic) else: table_name = name.lower() # 將表名變成小寫(xiě) filed_dic = {} # 定義一個(gè)空的列表,用來(lái)裝dic中屬于BaseFiled類(lèi)型的屬性,因?yàn)閐ic中會(huì)有其他創(chuàng)建類(lèi)時(shí)自動(dòng)生成的屬性,這些屬性我們沒(méi)必要去建立映射關(guān)系,所以需要將其剔除掉 for k, v in dic.items(): if isinstance(v, BaseFiled): filed_dic[k] = v dic["t_name"] = table_name # 將表名添加到dic中,實(shí)現(xiàn)類(lèi)名與表名的映射關(guān)系 dic["filed_dict"] = filed_dic # 將屬于BaseFiled類(lèi)型的屬性給添加到dic中,實(shí)現(xiàn)屬性與字段的映射關(guān)系 return super().__new__(cls, name, bases, dic) class BaseMode(metaclass=MyMateClass): def __init__(self, **kwargs): """ 由于每一個(gè)模型類(lèi)(也就是數(shù)據(jù)庫(kù)表)的屬性個(gè)數(shù)不一致,所以我們需要定義一個(gè)父類(lèi)來(lái)進(jìn)行定義初始化的屬性 :param kwargs: """ for k, v in kwargs.items(): # 遍歷傳進(jìn)來(lái)的所有屬性 setattr(self, k, v) # 拿到這些屬性后對(duì)self(也就是類(lèi)本身)進(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())) 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)
1、簡(jiǎn)單易用,與C/C++、Java、C# 等傳統(tǒng)語(yǔ)言相比,Python對(duì)代碼格式的要求沒(méi)有那么嚴(yán)格;2、Python屬于開(kāi)源的,所有人都可以看到源代碼,并且可以被移植在許多平臺(tái)上使用;3、Python面向?qū)ο螅軌蛑С置嫦蜻^(guò)程編程,也支持面向?qū)ο缶幊蹋?、Python是一種解釋性語(yǔ)言,Python寫(xiě)的程序不需要編譯成二進(jìn)制代碼,可以直接從源代碼運(yùn)行程序;5、Python功能強(qiáng)大,擁有的模塊眾多,基本能夠?qū)崿F(xiàn)所有的常見(jiàn)功能。
上述內(nèi)容就是使用Python怎么實(shí)現(xiàn)一個(gè)ORM模型,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。