国产睡熟迷奷白丝护士系列精品,中文色字幕网站,免费h网站在线观看的,亚洲开心激情在线

      <sup id="hb9fh"></sup>
          1. 千鋒教育-做有情懷、有良心、有品質(zhì)的職業(yè)教育機(jī)構(gòu)

            手機(jī)站
            千鋒教育

            千鋒學(xué)習(xí)站 | 隨時(shí)隨地免費(fèi)學(xué)

            千鋒教育

            掃一掃進(jìn)入千鋒手機(jī)站

            領(lǐng)取全套視頻
            千鋒教育

            關(guān)注千鋒學(xué)習(xí)站小程序
            隨時(shí)隨地免費(fèi)學(xué)習(xí)課程

            當(dāng)前位置:首頁  >  技術(shù)干貨  > Python元類之通過元類實(shí)現(xiàn)數(shù)據(jù)庫ORM框架

            Python元類之通過元類實(shí)現(xiàn)數(shù)據(jù)庫ORM框架

            來源:千鋒教育
            發(fā)布人:xqq
            時(shí)間: 2023-11-07 13:44:46 1699335886

            ORM框架是什么

            如果是沒有做過后端的小伙伴上來估計(jì)會(huì)有點(diǎn)蒙,這個(gè)ORM框架究竟是什么?ORM框架是后端工程師常用的一個(gè)框架,它的英文全稱是ObjectRelationalMapping,即對(duì)象-關(guān)系映射框架。顧名思義就是把關(guān)系轉(zhuǎn)化成對(duì)象的框架,關(guān)系這個(gè)詞我們在哪里用的最多呢?

            顯然應(yīng)該是數(shù)據(jù)庫。之前我們在分布式的文章介紹關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫的時(shí)候就著重介紹過關(guān)系的含義。我們常用的MySQL就是經(jīng)典的關(guān)系型數(shù)據(jù)庫,它存儲(chǔ)的形式是表,但是表承載的數(shù)據(jù)其實(shí)是兩個(gè)實(shí)體之間的"關(guān)系"。比如學(xué)生上課這個(gè)場景,學(xué)生和課程是兩個(gè)主體(entity),我們要記錄的是這兩個(gè)主體之間的關(guān)系,也就是學(xué)生上課這件事。

            而ORM框架做的事情是將這些關(guān)系映射成類,這樣我們可以將這張表當(dāng)中增刪改查的功能抽象成類當(dāng)中的方法。這樣我們就可以通過調(diào)用類的方式來操作數(shù)據(jù)庫了,從而達(dá)到高度抽象業(yè)務(wù)邏輯、降低用戶使用難度的目的。

            比如Java后端工程師常用的hibernate和ibatis都是用來做這件事情的,明確了框架的功能之后,我們先來設(shè)想一下最后的成果。假設(shè)我們現(xiàn)在開發(fā)出來了這么一套框架,那么它用起來的感覺應(yīng)該是怎樣的?

            我們來看下一個(gè)例子:

            classUser(Model):

            #定義類的屬性到列的映射:

            id=IntegerField('id')

            name=StringField('username')

            email=StringField('email')

            password=StringField('password')

            User類代表了數(shù)據(jù)庫當(dāng)中的一張表,它有4個(gè)字段:id,name,email和password,我們在定義字段的同時(shí)也通過類別指定了它們的類型。這個(gè)應(yīng)該不難理解,上面的這個(gè)類等價(jià)于我們在數(shù)據(jù)庫當(dāng)中執(zhí)行了這么一段建表的SQL:

            createtableifnotexistsuser(

            idint,

            namestring,

            emailstring,

            passwordstring

            )

            我們定義了表字段之后,接下來要做的就是根據(jù)字段創(chuàng)建數(shù)據(jù)了,其實(shí)也就是根據(jù)類創(chuàng)建實(shí)例。我們希望User類型的實(shí)例就對(duì)應(yīng)User表當(dāng)中的一條記錄,并且我們可以通過調(diào)用實(shí)例當(dāng)中的方法,來操作這張表進(jìn)行增刪改查。

            #創(chuàng)建一個(gè)實(shí)例:

            u=User(id=12345,name='Michael',email='test@orm.org',password='my-pwd')

            #保存到數(shù)據(jù)庫:

            u.save()

            那么,我們怎樣可以實(shí)現(xiàn)這樣的功能呢?

            功能實(shí)現(xiàn)

            我們先從簡單的功能開始實(shí)現(xiàn),首先是Field類,F(xiàn)ield類表示數(shù)據(jù)庫表當(dāng)中一個(gè)字段的類型。這里的邏輯很容易理清楚,我們需要定義多種類型,比如IntegerField和StringField。我們可以對(duì)這些field類抽象出一個(gè)父類來:

            classField(object):

            def__init__(self,name,column_type):

            self.name=name

            self.column_type=column_type

            def__str__(self):

            return'<{}:{}>'.format(self.__class__.__name__,self.name)

            __str__方法當(dāng)中打印出來的兩個(gè)字段,分別是類別的名稱和字段的名稱,這段代碼應(yīng)該不難理解。

            接著,我們實(shí)現(xiàn)它的兩個(gè)子類,分別是IntegerField和StringField:

            classStringField(Field):

            def__init__(self,name):

            super(StringField,self).__init__(name,'varchar(100)')

            classIntegerField(Field):

            def__init__(self,name):

            super(IntegerField,self).__init__(name,'bigint')

            這里也不難理解,只是一個(gè)簡單的繼承應(yīng)用而已。

            接下來就到了最關(guān)鍵的部分,也就是Model類的實(shí)現(xiàn)。我們先來分析一下我們希望Model這個(gè)類擁有的功能,由于它是我們定義出來的每一張表的父類,所以它應(yīng)該能夠獲取子類當(dāng)中的字段,并且將它存放在一個(gè)容器當(dāng)中。由于我們需要存儲(chǔ)的是字段名和類型的映射,所以將它存儲(chǔ)在dict當(dāng)中比較合理。

            另外一個(gè)功能是我們希望它能夠提供增刪改查的接口,能夠根據(jù)子類當(dāng)中定義的字段自動(dòng)生成相應(yīng)的SQL語句去調(diào)用數(shù)據(jù)庫。這個(gè)也是ORM框架的意義所在。

            第二個(gè)功能容易實(shí)現(xiàn),只要第一個(gè)功能搞定了,做一下字符串處理即可。但是第一個(gè)功能有些麻煩,它也是元類的意義所在。因?yàn)楦割惍?dāng)中的方法是無法獲取子類中定義的類屬性的,只能通過元類,在構(gòu)建類的時(shí)候可以拿到屬性的信息。

            所以我們已經(jīng)很明確了,我們實(shí)現(xiàn)元類的目的就是為了實(shí)現(xiàn)這個(gè)功能。理清楚了之后,再來寫代碼就不難了。我們先來實(shí)現(xiàn)這個(gè)元類:

            classModelMetaclass(type):

            def__new__(cls,name,bases,attrs):

            #創(chuàng)建model類的時(shí)候不做任何處理

            ifname=='Model':

            returntype.__new__(cls,name,bases,attrs)

            #打印表名的信息

            print('Foundmodel:%s'%name)

            #mappings用來存儲(chǔ)字段的信息

            mappings=dict()

            fork,vinattrs.items():

            #判斷v的類型,只有是Field的子類才會(huì)存儲(chǔ)起來

            ifisinstance(v,Field):

            print('Foundmapping:%s==>%s'%(k,v))

            mappings[k]=v

            #將mappings當(dāng)中的數(shù)據(jù)從類屬性當(dāng)中移除,防止關(guān)鍵字沖突

            forkinmappings.keys():

            attrs.pop(k)

            attrs['__mappings__']=mappings#保存屬性和列的映射關(guān)系

            attrs['__table__']=name#假設(shè)表名和類名一致

            returntype.__new__(cls,name,bases,attrs)

            如果你看過之前的文章,對(duì)元類已經(jīng)很熟悉了,那么這段代碼對(duì)你來說應(yīng)該不難理解。元類搞定了,剩下的Model就更簡單了。按照規(guī)范,我們需要實(shí)現(xiàn)增刪改查四個(gè)函數(shù),但是這里我們只是為了展示,所以就只實(shí)現(xiàn)其中一個(gè)作為例子,其他幾個(gè)都可以如法炮制。

            classModel(dict,metaclass=ModelMetaclass):

            def__init__(self,**kw):

            #由于Model的基類是dict,所以創(chuàng)造Model的字段會(huì)被解析成dict的構(gòu)造參數(shù)

            #也就是說字段名和字段值的映射會(huì)存儲(chǔ)在dict當(dāng)中

            super(Model,self).__init__(**kw)

            def__getattr__(self,key):

            try:

            returnself[key]

            exceptKeyError:

            raiseAttributeError(r"'Model'objecthasnoattribute'%s'"%key)

            def__setattr__(self,key,value):

            self[key]=value

            defsave(self):

            fields=[]

            params=[]

            args=[]

            fork,vinself.__mappings__.items():

            #fields存儲(chǔ)字段名

            fields.append(v.name)

            #params填充問號(hào)

            params.append('?')

            #獲取字段的值

            args.append(getattr(self,k,None))

            sql='insertinto%s(%s)values(%s)'%(self.__table__,','.join(fields),','.join(params))

            print('SQL:%s'%sql)

            print('ARGS:%s'%str(args))

            Model當(dāng)中的save方法不難看懂,但是前面的幾個(gè)方法看起來有些多余。但實(shí)際上它們也很重要,這里有一個(gè)關(guān)鍵信息是Model類的父類是dict,我們在構(gòu)建Model的時(shí)候傳入的參數(shù)會(huì)被用來初始化一個(gè)dict。所以我們創(chuàng)建數(shù)據(jù)實(shí)例的時(shí)候數(shù)據(jù)的名稱和數(shù)據(jù)值的映射會(huì)被存儲(chǔ)在dict當(dāng)中,所以我們在save方法當(dāng)中才會(huì)從self的attr當(dāng)中獲取字段的值。并且我們在初始化User的時(shí)候,也必須要填寫每個(gè)字段的名稱,原因就在這里。

            最后我們來運(yùn)行一下:

            從結(jié)果上來看,我們輸出了User這個(gè)類的插入SQL以及它的字段的值。只需要鏈接一下數(shù)據(jù)庫,我們的這個(gè)ORM框架就可以真正投入使用了。

            總結(jié)

            在整個(gè)ORM框架實(shí)現(xiàn)的過程當(dāng)中,最重要的是我們對(duì)Model這個(gè)類創(chuàng)建了元類,但是真正應(yīng)用的地方卻是在Model的子類。實(shí)際上在實(shí)際創(chuàng)建User類的時(shí)候,解釋器會(huì)先搜索User內(nèi)部是否定義了元類,如果沒有,會(huì)上一層去往User的父類也就是Model類搜索元類,如果找到了元類,就會(huì)使用元類來創(chuàng)建User。相當(dāng)于元類被隱形地繼承了下來,但是我們在使用子類的時(shí)候卻感知不到。

            對(duì)于框架的使用者來說,也的確不需要了解框架內(nèi)部的實(shí)現(xiàn)機(jī)制,只需要明白使用方法,照著使用就行了。雖然元類的實(shí)現(xiàn)和理解很復(fù)雜,但是使用起來卻很簡單,這也是它的一個(gè)顯著特點(diǎn)。

            以上內(nèi)容為大家介紹了Python元類之通過元類實(shí)現(xiàn)數(shù)據(jù)庫ORM框架,希望對(duì)大家有所幫助,如果想要了解更多Python相關(guān)知識(shí),請(qǐng)關(guān)注IT培訓(xùn)機(jī)構(gòu):千鋒教育。

            聲明:本站稿件版權(quán)均屬千鋒教育所有,未經(jīng)許可不得擅自轉(zhuǎn)載。
            10年以上業(yè)內(nèi)強(qiáng)師集結(jié),手把手帶你蛻變精英
            請(qǐng)您保持通訊暢通,專屬學(xué)習(xí)老師24小時(shí)內(nèi)將與您1V1溝通
            免費(fèi)領(lǐng)取
            今日已有369人領(lǐng)取成功
            劉同學(xué) 138****2860 剛剛成功領(lǐng)取
            王同學(xué) 131****2015 剛剛成功領(lǐng)取
            張同學(xué) 133****4652 剛剛成功領(lǐng)取
            李同學(xué) 135****8607 剛剛成功領(lǐng)取
            楊同學(xué) 132****5667 剛剛成功領(lǐng)取
            岳同學(xué) 134****6652 剛剛成功領(lǐng)取
            梁同學(xué) 157****2950 剛剛成功領(lǐng)取
            劉同學(xué) 189****1015 剛剛成功領(lǐng)取
            張同學(xué) 155****4678 剛剛成功領(lǐng)取
            鄒同學(xué) 139****2907 剛剛成功領(lǐng)取
            董同學(xué) 138****2867 剛剛成功領(lǐng)取
            周同學(xué) 136****3602 剛剛成功領(lǐng)取
            相關(guān)推薦HOT