最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2021年11月24日 15:42:16   作者:馬兒不會跑  
Python中的類與數(shù)據(jù)庫之間的映射,對數(shù)據(jù)的操作就不用編寫SQL語言了,因為都封裝好了,比如你想插入一條數(shù)據(jù),你就直接創(chuàng)建一個對象即可,下面通過本文學習下python利用元類和描述器實現(xiàn)ORM模型的詳細步驟,感興趣的朋友一起看看吧

ORM模型:

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

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

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

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

大致就是上面的映射關系

ORM實現(xiàn)步驟:

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

元類:

1.實例對象是通過類來創(chuàng)建,那類又是通過什么創(chuàng)建的呢?python中所有的類都是通過元類來創(chuàng)建類,且這個元類只有一個那就是type;

class Test:
    pass

t = Test()
print(type(Test))  #類是通過元類type創(chuàng)建
print(type(t))  #實例對象是通過類創(chuàng)建
#輸出-----------------------
<class 'type'>
<class '__main__.Test'>

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

#通過元類來創(chuàng)建類
test1 = type("test2",(object,),{"name":"xiaoming"})
t1 = test1()

print(type(test1))
print(type(t1))
#輸出---------------
<class 'type'>
<class '__main__.test2'>

自定義元類:

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

class MetaClass(type):
    """自定義一個元類,這個元類必須繼承type,用這個元類創(chuàng)建類時,必須使用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'>  #可以看到此時這個類創(chuàng)建是用我們自定義的元類創(chuàng)建的,而不是type創(chuàng)建的

描述器:

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

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 = "xiaoming"  #給描述器設置一個類屬性
print(t.name)  #獲取一個類屬性
#輸出---------------
設置屬性的時候會被調用
獲取屬性的時候會被調用
xiaoming

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

設置屬性一定會調用描述器里面的—set—方法,再設置屬性之前校驗這個屬性長度,類型等等,如果不符合要求那就拋錯,如果符合那就設置成功;

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):
    """定義一個數(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

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

模型類,這些字段是通過描述器來進行長度和類型校驗的

class User():
"""這是一個模型類,相當于定義了一個表名是User的表,表有三個字段name,age,love"""
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)

如果是這樣的話我們給這個類實例化的時候,需要這樣傳值:

t1 = User()
t1.name = "xiaoming"
t1.age = 18
t1.love = "single"

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

class BaseMode():

    def __init__(self, **kwargs):
        """
        由于每一個模型類(也就是數(shù)據(jù)庫表)的屬性個數(shù)不一致,所以我們需要定義一個父類來進行定義初始化的屬性
        :param kwargs:
        """
        for k, v in kwargs.items():   # 遍歷傳進來的所有屬性
            setattr(self, k, v)   # 拿到這些屬性后對self(也就是類本身)進行設置屬性

class User(BaseMode):
"""第一個模型類"""
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)

t1 = User(name= "xiaoming",age=18,love="xxx")#現(xiàn)在我們就可以一次傳入多個值,并且參數(shù)個數(shù)也不限定

class Oder(BaseMode):
    """第二個模型類"""
    id = CharFiled()
    count = IntFiled()
    
t2 = Oder(id ="a1",count = 123)

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

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

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

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

class BaseMode(metaclass=MetaClass):

    def __init__(self, **kwargs):
        """
        由于每一個模型類(也就是數(shù)據(jù)庫表)的屬性個數(shù)不一致,所以我們需要定義一個父類來進行定義初始化的屬性
        :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()))
        print(sql)
        return sql

class User(BaseMode):
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)


class Oder(BaseMode):
    """第二個模型類"""
    id = CharFiled()
    count = IntFiled()

t2 = Oder(id ="a1",count = 123)#實例化模型類,并調用save方法,即可向數(shù)據(jù)庫插入數(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')

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

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


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):
    """定義一個數(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):
        """
        由于每一個模型類(也就是數(shù)據(jù)庫表)的屬性個數(shù)不一致,所以我們需要定義一個父類來進行定義初始化的屬性
        :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()))
        print(sql)
        return sql

class User(BaseMode):
    name = CharFiled()
    age = IntFiled()
    love = CharFiled(length=50)


class Oder(BaseMode):
    """第二個模型類"""
    id = CharFiled()
    count = IntFiled()

t2 = Oder(id ="a1",count = 123)
t2.save()

t1 = User(name= "xiaoming",age=18,love="xxx")
t1.save()

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

相關文章

  • 巧用Python裝飾器 免去調用父類構造函數(shù)的麻煩

    巧用Python裝飾器 免去調用父類構造函數(shù)的麻煩

    巧用Python裝飾器 免去調用父類構造函數(shù)的麻煩,需要的朋友可以參考下
    2012-05-05
  • pytest-sugar?執(zhí)行過程中顯示進度條的腳本分享

    pytest-sugar?執(zhí)行過程中顯示進度條的腳本分享

    Pytest-sugar是一款用來改善控制臺顯示的插件,增加了進度條顯示,使得在用例執(zhí)行過程中可以看到進度條,而且進度條是根據(jù)用例是否通過標注不同顏色,非常醒目,接下來通過本文給大家分享下pytest?sugar?顯示進度條的腳本,感興趣的朋友一起看看吧
    2022-12-12
  • Python中的星號*還能這么用你知道嗎

    Python中的星號*還能這么用你知道嗎

    這篇文章主要為大家詳細介紹了Python中的星號*用法的相關資料,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-06-06
  • python解釋器安裝教程的方法步驟

    python解釋器安裝教程的方法步驟

    這篇文章主要介紹了python解釋器安裝教程的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • python數(shù)據(jù)分析之公交IC卡刷卡分析

    python數(shù)據(jù)分析之公交IC卡刷卡分析

    這篇文章主要介紹了python數(shù)據(jù)分析之公交IC卡,文中有非常詳細的代碼示例,對正在學習python的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-04-04
  • Python 代碼性能優(yōu)化技巧分享

    Python 代碼性能優(yōu)化技巧分享

    選擇了腳本語言就要忍受其速度,這句話在某種程度上說明了 python 作為腳本的一個不足之處,那就是執(zhí)行效率和性能不夠理想,特別是在 performance 較差的機器上,因此有必要進行一定的代碼優(yōu)化來提高程序的執(zhí)行效率
    2012-08-08
  • 用uWSGI和Nginx部署Flask項目的方法示例

    用uWSGI和Nginx部署Flask項目的方法示例

    這篇文章主要介紹了用uWSGI和Nginx部署Flask項目的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • 詳解python函數(shù)傳參傳遞dict/list/set等類型的問題

    詳解python函數(shù)傳參傳遞dict/list/set等類型的問題

    這篇文章主要介紹了詳解python函數(shù)傳參傳遞dict/list/set等類型的問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • Python檢測QQ在線狀態(tài)的方法

    Python檢測QQ在線狀態(tài)的方法

    這篇文章主要介紹了Python檢測QQ在線狀態(tài)的方法,涉及Python通過第三方平臺檢測QQ在線狀態(tài)的技巧,非常簡單實用,需要的朋友可以參考下
    2015-05-05
  • windows+vscode安裝paddleOCR運行環(huán)境的步驟

    windows+vscode安裝paddleOCR運行環(huán)境的步驟

    這篇文章主要介紹了windows+vscode安裝paddleOCR運行環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11

最新評論

仁寿县| 高要市| 会同县| 綦江县| 长垣县| 九寨沟县| 施秉县| 乌拉特中旗| 巴林右旗| SHOW| 兴和县| 铁岭市| 泸水县| 临沂市| 定陶县| 太谷县| 井冈山市| 芷江| 金华市| 新邵县| 孝义市| 东阿县| 隆化县| 璧山县| 光山县| 菏泽市| 日喀则市| 巩义市| 吴忠市| 长岭县| 金阳县| 九台市| 南康市| 上饶市| 瑞丽市| 甘谷县| 兴义市| 工布江达县| 邯郸县| 舞阳县| 揭西县|