欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

ORM對(duì)象關(guān)系映射框架基本搭建

一 概念

1 概念

ORM :對(duì)象關(guān)系映射,對(duì)象和關(guān)系之間的映射,使用面向?qū)ο蟮姆绞絹?lái)操作數(shù)據(jù)庫(kù)

創(chuàng)新互聯(lián)建站主要從事網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)久治,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):18980820575


關(guān)系對(duì)象模型和python對(duì)象模型之間的映射


tabel => class ,表映射類
row => object ,行映射為實(shí)例
column=> property ,字段映射屬性

2 舉例

表有l(wèi)ogin,字段為id int , username varchar, age int
映射到python為

#!/usr/bin/poython3.6
#conding:utf-8

class  Login:
    # 此處的INTX 是int類型的類 
    #  VARY 是varchar類型的類
    id=INTX()
    username=VARY()
    age=INTX()
# 最終得到 
class Login:
    def __init__(self):
        self.id=1
        self.username='admin'
        self.age=20

二 實(shí)現(xiàn)ORM 框架

1 字段類的實(shí)現(xiàn)

字段有name,字段名稱為column,類型為type,是否主鍵pk,是否唯一鍵unique,是否索引index,是否可為空nullable,默認(rèn)值default,是否自增等,這些都是字段的特征,所以字段可以使用類來(lái)描述。

字段類要提供對(duì)數(shù)據(jù)的校驗(yàn)功能,如聲明字段類型為int類型,應(yīng)該要判斷數(shù)據(jù)是不是整數(shù)類形。
字段有多種類型,不同類型有差異,使用繼承的方式實(shí)現(xiàn)。
字段現(xiàn)在定義為類屬性,而這個(gè)類屬性又適合使用類來(lái)描述,這就是描述器了。


1 定義基類,用于實(shí)現(xiàn)所有類的基礎(chǔ)類型

#!/usr/bin/poython3.6
#conding:utf-8

class  Field:
    def __init__(self,name,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        self.name=name  # 字段名稱
        if  column  is None:  #列名稱
            self.column=self.name
        else:
            self.column=column
        self.pk=pk  # 主鍵
        self.unique=unique  #唯一
        self.index=index #索引
        self.nullable=nullable  #是否為空
        self.default=default  # 默認(rèn)是否為空
    def  validate(self,value):  # 此處定義數(shù)據(jù)校驗(yàn)方式,每種不同類型的校驗(yàn)方式不同,因此應(yīng)該在子類中分別實(shí)現(xiàn)
        raise  NotImplementedError  #基類不實(shí)現(xiàn)此功能

    def __get__(self, instance, owner): #此處用于定義描述器,此處當(dāng)子類的類調(diào)用此屬性時(shí),會(huì)返回對(duì)應(yīng)的值
        # 此處的self表示父類的實(shí)例,instance表示子類的實(shí)例,owner表示子類的類
        # pass
        if instance is None:  #此處為None表示子類未生成對(duì)應(yīng)實(shí)例
            return self  # 此處的self表示實(shí)例自己
        return  instance.__dict__[self.name]  # 返回實(shí)例對(duì)應(yīng)的字段名稱
    def __set__(self, instance, value): #此處用于定義數(shù)據(jù)描述器,用于子類實(shí)例調(diào)用時(shí)使用,用于返回對(duì)應(yīng)的結(jié)果
        # instace 表示子類的實(shí)例,其相關(guān)的信息應(yīng)該被存儲(chǔ)于子類實(shí)例中,
        self.validate(value)
        instance.__dict__[self.name]=value

    def  __str__(self):
        return   "{} <{}>".format(self.__class__.__name__,self.name)  # 此處返回被調(diào)用的類名和實(shí)例名稱
    __repr__=__str__
# 定義整數(shù)類型的類型屬性
class  IntField(Field):  #多了自增屬性。
    def  __init__(self,name,column=None,pk=False,unique=False,index=False,nullable=True,default=None,auto_increment=True):
        self.auto_increment=auto_increment
        super().__init__(name,column,pk,unique,index,nullable,default)

    def validate(self,value):
        if value is  None:
            if self.pk:  # 主鍵不能為空,因此此處會(huì)報(bào)錯(cuò)
                raise TypeError("{}:{}".format(self.name,value))
            if not self.nullable:  # 當(dāng)定義了非空時(shí),上述的值為空,則報(bào)錯(cuò)
                raise TypeError
        else:
            if not isinstance(value,int):  #若數(shù)據(jù)的類型為非int,則報(bào)錯(cuò)
                raise TypeError("{}  is  not  int,  It's {}".format(self.name,type(value)))

# 定義字符串的類型屬性
class  StringField(Field):  #定義字符串屬性類
    # 增加了字符串長(zhǎng)度的定義
    def __init__(self,length=32,name=None,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        super().__init__(name,column,pk,unique,index,nullable,default)  #此處的屬性可以繼承父類的屬性
        self.length=length  #此處用于定義字符串類型的長(zhǎng)度
    def  validate(self,value):  #此處用于定義各自的屬性檢查,對(duì)數(shù)據(jù)進(jìn)行屬性檢查
        if  value  is None: # 此處的None對(duì)應(yīng)數(shù)據(jù)庫(kù)的null
            if self.pk:  # 如果數(shù)據(jù)是None,而其定義了主鍵,則會(huì)報(bào)錯(cuò),因?yàn)橹麈I必須不能是Null,主鍵非空且唯一
                raise TypeError("{} is pk,not None".format(self.name))
            if not  self.nullable:  # 如果其是None,而定義的是非null,則會(huì)報(bào)錯(cuò)
                raise TypeError("{}  is  not  null".format(self.name))
        else:
            if not isinstance(value,str):
                raise TypeError("{} should be string".format(self.name))
            if len(value) > self.length:  #真實(shí)的值大于規(guī)定的值,則會(huì)報(bào)錯(cuò)
                raise ValueError("{} is to long value={}".format(self.name,value))

2 Login 類的實(shí)現(xiàn)

# 具體類的實(shí)現(xiàn)

class  Login:
    id=IntField('id','id',pk=True,nullable=False,auto_increment=True)  # 此種調(diào)用方式會(huì)啟動(dòng)get方法的調(diào)用,從而返回實(shí)例自己
    name=StringField(length=64,name='username',nullable=False)
    age=IntField('age')
    def  __init__(self,id,nane,age):
        self.id=id
        self.name=name
        self.age=age
    def __str__(self):
        return   "Loin({},{},{})".format(self.id,self.name,self.age)
    __repr__=__str__

Login 類的操作
Login類的操作對(duì)應(yīng)表的CRUD操作,及增刪改查,如果使用pyMySQL,應(yīng)該使用cursor對(duì)象的execute方法,增加數(shù)據(jù),修改數(shù)據(jù)定義為save方法,為L(zhǎng)ogin類增加此方法,數(shù)據(jù)庫(kù)的鏈接要求從外面?zhèn)魅?/p>

具體實(shí)現(xiàn)如下

# 具體類的實(shí)現(xiàn)

# 具體類的實(shí)現(xiàn)

class  Login:
    id=IntField('id','id',pk=True,nullable=False,auto_increment=True)
    name=StringField(length=64,name='username',nullable=False)
    age=IntField('age')
    def  __init__(self,id,nane,age):
        self.id=id
        self.name=name
        self.age=age
    def __str__(self):
        return   "Loin({},{},{})".format(self.id,self.name,self.age)
    __repr__=__str__

    def save(self,conn:pymysql.connections.Connection):
        sql="insert into  login(id,bane,age)  values(%s,%s,%s)"
        with conn as cursor:
            cursor.execute(sql,(self.id,self.name,self.age))

3 session類的實(shí)現(xiàn)

每一次數(shù)據(jù)庫(kù)操作都是在一個(gè)會(huì)話中完成的,將cursor的操作封裝在會(huì)話中

class  Session:  #此處用以封裝鏈接,可在此處增加上下文支持
    def __init__(self,conn:pymysql.connections.Connection):
        self.conn=conn
        self.cursor=None
    def execute(self,query,*args):
        if self.cursor is None:
            self.cursor=self.conn.cursor()
        self.cursor.execute(query,args)
    def __enter__(self): # 此處實(shí)現(xiàn)方式和
        return self.conn.cursor()

        # self.cursor=self.conn.cursor()
        # return self 如此寫,這個(gè)session必須是一個(gè)線程級(jí)別的,如果用進(jìn)程,則直接覆蓋cursor
        # #因?yàn)榫€程是順序執(zhí)行的,都用新的cursor()當(dāng)查詢數(shù)據(jù)時(shí),數(shù)據(jù)找不到了,因?yàn)閏ursor變了。本session是在線程內(nèi)執(zhí)行,不能夸線程執(zhí)行

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        if exc_type: # 此處用于定義是否出錯(cuò),若出錯(cuò),則直接返回
            self.conn.rollback()
        else:
            self.conn.commit()

class  Login:
    id=IntField('id','id',pk=True,nullable=False,auto_increment=True)
    name=StringField(length=64,name='username',nullable=False)
    age=IntField('age')
    def  __init__(self,id,name,age):
        self.id=id
        self.name=name
        self.age=age
    def __str__(self):
        return   "Loin({},{},{})".format(self.id,self.name,self.age)
    __repr__=__str__

    def save(self,session:Session):
        sql="insert  into  login(id,name,age)  values(%s,%s,%s)"
        with  session as cursor:  # 此處直接調(diào)用enter返回cursor游標(biāo),此處的最后會(huì)關(guān)閉游標(biāo),但不會(huì)關(guān)閉鏈接
            with cursor:  # 此處使用游標(biāo)的屬性進(jìn)行處理 
                cursor.execute(sql,(self.id,self.name,self.age))

4 Model 類的實(shí)現(xiàn)

Login 這樣的類,如果多建立幾個(gè),其都是一個(gè)樣子,每一個(gè)這樣的類,得定義一個(gè)名稱對(duì)應(yīng)不同的表,都需要先定義好類,再定義__init__初始化值,而這些值剛好是定義好的類屬性,操作也是一樣的。CRID

設(shè)計(jì),定義一個(gè)Model類,增加一個(gè)__table__類屬性來(lái)保存不同的表名稱

class  Model:
    def save(self,session:Session=None):
        names=[]
        values=[]
        for k,v  in self.__class__.__dict__.items():  # 此處用于獲取實(shí)例的名稱和其對(duì)應(yīng)的值
            # print ('for',k,'---',v)
            if  isinstance(v,Field):  # 此處若屬于基類
                if  k in self.__dict__.keys():  # 此處的字段符合
                    names.append(k)
                    values.append(v)
        # __table__  # 此處在子類中添加
        query="insert into {} ({}) values ({})".format(self.__table__,",".join(names),",".join(["%s"]*len(values))) # 此處是匹配對(duì)應(yīng)的sql
        print (query)
        print (values)

class  Login(Model):
    id=IntField('id','id',pk=True,nullable=False,auto_increment=True)
    name=StringField(length=64,name='name',nullable=False)
    age=IntField('age')
    __table__='Login'
    def  __init__(self,id,name,age):
        self.id=id
        self.name=name
        self.age=age
    def __str__(self):
        return   "Loin({},{},{})".format(self.id,self.name,self.age)
    __repr__=__str__

5 使用元類改造Model

編寫一個(gè)元類ModelMeta
以它作為元類的類,都可以獲得一個(gè)類屬性
如果沒(méi)有定義_table_,就自動(dòng)加上這個(gè)屬性,值為類名
可以遍歷類屬性,找出定義的字段類,建立一張映射表mapping
找出主鍵字段primarykey

#!/usr/bin/poython3.6
#conding:utf-8
import  pymysql
class  Field:
    def __init__(self,name,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        self.name=name  # 字段名稱
        if  column  is None:  #列名稱
            self.column=self.name
        else:
            self.column=column
        self.pk=pk  # 主鍵
        self.unique=unique  #唯一
        self.index=index #索引
        self.nullable=nullable  #是否為空
        self.default=default  # 默認(rèn)是否為空
    def  validate(self,value):  # 此處定義數(shù)據(jù)校驗(yàn)方式,每種不同類型的校驗(yàn)方式不同,因此應(yīng)該在子類中分別實(shí)現(xiàn)
        raise  NotImplementedError  #基類不實(shí)現(xiàn)此功能

    def __get__(self, instance, owner): #此處用于定義描述器,此處當(dāng)子類的類調(diào)用此屬性時(shí),會(huì)返回對(duì)應(yīng)的值
        # 此處的self表示父類的實(shí)例,instance表示子類的實(shí)例,owner表示子類的類
        # pass
        if instance is None:  #此處為None表示子類未生成對(duì)應(yīng)實(shí)例
            return self  # 此處的self表示實(shí)例自己
        return  instance.__dict__[self.name]  # 返回實(shí)例對(duì)應(yīng)的字段名稱
    def __set__(self, instance, value): #此處用于定義數(shù)據(jù)描述器,用于子類實(shí)例調(diào)用時(shí)使用,用于返回對(duì)應(yīng)的結(jié)果
        # instace 表示子類的實(shí)例,其相關(guān)的信息應(yīng)該被存儲(chǔ)于子類實(shí)例中,
        self.validate(value)
        instance.__dict__[self.name]=value #此處的name是字段名,value是子類的self,對(duì)應(yīng)的屬性的值,及真實(shí)的數(shù)據(jù)

    def  __str__(self):
        return   "{} <{}>".format(self.__class__.__name__,self.name)  # 此處返回被調(diào)用的類名和實(shí)例名稱
    __repr__=__str__
# 定義整數(shù)類型的類型屬性
class  IntField(Field):  #多了自增屬性。
    def  __init__(self,name=None,column=None,pk=False,unique=False,index=False,nullable=True,default=None,auto_increment=True):
        self.auto_increment=auto_increment
        super().__init__(name,column,pk,unique,index,nullable,default)

    def validate(self,value):
        if value is  None:
            if self.pk:  # 主鍵不能為空,因此此處會(huì)報(bào)錯(cuò)
                raise TypeError("{}:{}".format(self.name,value))
            if not self.nullable:  # 當(dāng)定義了非空時(shí),上述的值為空,則報(bào)錯(cuò)
                raise TypeError
        else:
            if not isinstance(value,int):  #若數(shù)據(jù)的類型為非int,則報(bào)錯(cuò)
                raise TypeError("{}  is  not  int,  It's {}".format(self.name,type(value)))

# 定義字符串的類型屬性
class  StringField(Field):  #定義字符串屬性類
    # 增加了字符串長(zhǎng)度的定義
    def __init__(self,length=32,name=None,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        super().__init__(name,column,pk,unique,index,nullable,default)  #此處的屬性可以繼承父類的屬性
        self.length=length  #此處用于定義字符串類型的長(zhǎng)度
    def  validate(self,value):  #此處用于定義各自的屬性檢查,對(duì)數(shù)據(jù)進(jìn)行屬性檢查
        if  value  is None: # 此處的None對(duì)應(yīng)數(shù)據(jù)庫(kù)的null
            if self.pk:  # 如果數(shù)據(jù)是None,而其定義了主鍵,則會(huì)報(bào)錯(cuò),因?yàn)橹麈I必須不能是Null,主鍵非空且唯一
                raise TypeError("{} is pk,not None".format(self.name))
            if not  self.nullable:  # 如果其是None,而定義的是非null,則會(huì)報(bào)錯(cuò)
                raise TypeError("{}  is  not  null".format(self.name))
        else:
            if not isinstance(value,str):
                raise TypeError("{} should be string".format(self.name))
            if len(value) > self.length:  #真實(shí)的值大于規(guī)定的值,則會(huì)報(bào)錯(cuò)
                raise ValueError("{} is to long value={}".format(self.name,value))

# 具體類的實(shí)現(xiàn)
class  Session:  #此處用以封裝鏈接,可在此處增加上下文支持
    def __init__(self,conn:pymysql.connections.Connection):
        self.conn=conn
        self.cursor=None
    def execute(self,query,*args):
        if self.cursor is None:
            self.cursor=self.conn.cursor()
        self.cursor.execute(query,args)
    def __enter__(self): # 此處實(shí)現(xiàn)方式和
        return self.conn.cursor()

        # self.cursor=self.conn.cursor()
        # return self 如此寫,這個(gè)session必須是一個(gè)線程級(jí)別的,如果用進(jìn)程,則直接覆蓋cursor
        # #因?yàn)榫€程是順序執(zhí)行的,都用新的cursor()當(dāng)查詢數(shù)據(jù)時(shí),數(shù)據(jù)找不到了,因?yàn)閏ursor變了。本session是在線程內(nèi)執(zhí)行,不能夸線程執(zhí)行

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        if exc_type: # 此處用于定義是否出錯(cuò),若出錯(cuò),則直接返回
            self.conn.rollback()
        else:
            self.conn.commit()

class ModeMetd(type):  # 子類構(gòu)建的時(shí)候?qū)崿F(xiàn)的
    def __new__(cls,name,bases,attrs:dict):  # 此處是在類的定義中進(jìn)行調(diào)用的,
        # 此處的name表示被調(diào)用子類的類名,而對(duì)應(yīng)的字典attrs則表示子類的屬性字典
        # name 類名,attrs類屬性字典
        if '__table__'  not in attrs.keys():
            attrs['__table__']=name   #默認(rèn)添加表名稱為類名稱

        mapping={}  # 方便后面查詢屬性名和字段實(shí)例
        primarykey=[]  # 多個(gè)主鍵的情況下使用,如果使用一個(gè)變量名,則導(dǎo)致后面覆蓋前面
        for k,v in attrs.items():  # k代表的是列名稱,v表示的是子類的類型
            if isinstance(v,Field):  # 此處判斷是否繼承與父類
                mapping[k]=v
                if  v.name is None:  # 此處用于處理子類的屬性的字典的列名稱處理問(wèn)題
                    v.name=k  # 如果是,則將類.name
                if  v.column is None:
                    v.column=v.name # 沒(méi)有給字段名,則使用類對(duì)應(yīng)的列名稱
                if v.pk:
                    primarykey.append(v)
        # 增加屬性
        attrs['__mapping__']=mapping
        attrs['__primarykey__']=primarykey
        return super().__new__(cls,name,bases,attrs)

class  Model(metaclass=ModeMetd):  # 實(shí)體類的調(diào)用時(shí)實(shí)現(xiàn),子類的實(shí)例調(diào)用時(shí)實(shí)現(xiàn)的
    def save(self,session:Session=None):
        names=[]
        values=[]
        for k,v  in self.__class__.__dict__.items():  # 此處用于獲取實(shí)例的名稱和其對(duì)應(yīng)的值
            # print ('for',k,'---',v)
            if  isinstance(v,Field):  # 此處若屬于基類
                if  k in self.__dict__.keys():  # 此處的字段符合
                    names.append(k)
                    values.append(self.__dict__[k]) # v是一個(gè)Field類型的實(shí)例,是子類和父類的實(shí)例
                    print (self.__dict__[k])  # 此處是實(shí)例。實(shí)例中的數(shù)字
        # __table__  # 此處在子類中添加
        query="insert into {} ({}) values ({})".format(self.__table__,",".join(names),",".join(["%s"]*len(values))) # 此處是匹配對(duì)應(yīng)的sql
        print (query)
        # with  session:
        #     session.execute(query,values)

class  Login(Model):
    id=IntField(pk=True,nullable=False,auto_increment=True)
    name=StringField(length=64,name='name',nullable=False)
    age=IntField()
    __table__='Login'
    def  __init__(self,id,name,age):
        self.id=id
        self.name=name
        self.age=age
    def __str__(self):
        return   "Loin({},{},{})".format(self.id,self.name,self.age)
    __repr__=__str__

l=Login(1,'admin',20)
l.save(None)
if __name__ == "__main__":
    pass

結(jié)果如下

ORM對(duì)象關(guān)系映射框架基本搭建

6 引擎類

實(shí)體類沒(méi)有提供數(shù)據(jù)庫(kù)連接,當(dāng)然也不應(yīng)該提供,實(shí)體類就應(yīng)該只完成表和類的映射。

提供一個(gè)數(shù)據(jù)庫(kù)的包裝類
1 負(fù)責(zé)數(shù)據(jù)庫(kù)連接
2 負(fù)責(zé)CRUD操作,取代實(shí)體類的CRUD方法

#!/usr/bin/poython3.6
#conding:utf-8
import  pymysql
class  Field:
    def __init__(self,name,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        self.name=name  # 字段名稱
        if  column  is None:  #列名稱
            self.column=self.name
        else:
            self.column=column
        self.pk=pk  # 主鍵
        self.unique=unique  #唯一
        self.index=index #索引
        self.nullable=nullable  #是否為空
        self.default=default  # 默認(rèn)是否為空
    def  validate(self,value):  # 此處定義數(shù)據(jù)校驗(yàn)方式,每種不同類型的校驗(yàn)方式不同,因此應(yīng)該在子類中分別實(shí)現(xiàn)
        raise  NotImplementedError  #基類不實(shí)現(xiàn)此功能

    def __get__(self, instance, owner): #此處用于定義描述器,此處當(dāng)子類的類調(diào)用此屬性時(shí),會(huì)返回對(duì)應(yīng)的值
        # 此處的self表示父類的實(shí)例,instance表示子類的實(shí)例,owner表示子類的類
        # pass
        if instance is None:  #此處為None表示子類未生成對(duì)應(yīng)實(shí)例
            return self  # 此處的self表示實(shí)例自己
        return  instance.__dict__[self.name]  # 返回實(shí)例對(duì)應(yīng)的字段名稱
    def __set__(self, instance, value): #此處用于定義數(shù)據(jù)描述器,用于子類實(shí)例調(diào)用時(shí)使用,用于返回對(duì)應(yīng)的結(jié)果
        # instace 表示子類的實(shí)例,其相關(guān)的信息應(yīng)該被存儲(chǔ)于子類實(shí)例中,
        self.validate(value)
        instance.__dict__[self.name]=value #此處的name是字段名,value是子類的self,對(duì)應(yīng)的屬性的值,及真實(shí)的數(shù)據(jù)

    def  __str__(self):
        return   "{} <{}>".format(self.__class__.__name__,self.name)  # 此處返回被調(diào)用的類名和實(shí)例名稱
    __repr__=__str__
# # 定義整數(shù)類型的類型屬性
class  IntField(Field):  #多了自增屬性。
    def  __init__(self,name=None,column=None,pk=False,unique=False,index=False,nullable=True,default=None,auto_increment=True):
        self.auto_increment=auto_increment
        super().__init__(name,column,pk,unique,index,nullable,default)

    def validate(self,value):
        if value is  None:
            if self.pk:  # 主鍵不能為空,因此此處會(huì)報(bào)錯(cuò)
                raise TypeError("{}:{}".format(self.name,value))
            if not self.nullable:  # 當(dāng)定義了非空時(shí),上述的值為空,則報(bào)錯(cuò)
                raise TypeError
        else:
            if not isinstance(value,int):  #若數(shù)據(jù)的類型為非int,則報(bào)錯(cuò)
                raise TypeError("{}  is  not  int,  It's {}".format(self.name,type(value)))

# 定義字符串的類型屬性
class  StringField(Field):  #定義字符串屬性類
    # 增加了字符串長(zhǎng)度的定義
    def __init__(self,length=32,name=None,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        super().__init__(name,column,pk,unique,index,nullable,default)  #此處的屬性可以繼承父類的屬性
        self.length=length  #此處用于定義字符串類型的長(zhǎng)度
    def  validate(self,value):  #此處用于定義各自的屬性檢查,對(duì)數(shù)據(jù)進(jìn)行屬性檢查
        if  value  is None: # 此處的None對(duì)應(yīng)數(shù)據(jù)庫(kù)的null
            if self.pk:  # 如果數(shù)據(jù)是None,而其定義了主鍵,則會(huì)報(bào)錯(cuò),因?yàn)橹麈I必須不能是Null,主鍵非空且唯一
                raise TypeError("{} is pk,not None".format(self.name))
            if not  self.nullable:  # 如果其是None,而定義的是非null,則會(huì)報(bào)錯(cuò)
                raise TypeError("{}  is  not  null".format(self.name))
        else:
            if not isinstance(value,str):
                raise TypeError("{} should be string".format(self.name))
            if len(value) > self.length:  #真實(shí)的值大于規(guī)定的值,則會(huì)報(bào)錯(cuò)
                raise ValueError("{} is to long value={}".format(self.name,value))

# 具體類的實(shí)現(xiàn)
class  Session:  #此處用以封裝鏈接,可在此處增加上下文支持
    def __init__(self,conn:pymysql.connections.Connection):
        self.conn=conn
        self.cursor=None
    def execute(self,query,*args):
        if self.cursor is None:
            self.cursor=self.conn.cursor()
        self.cursor.execute(query,args)
    def __enter__(self): # 此處實(shí)現(xiàn)方式和
        return self.conn.cursor()

        # self.cursor=self.conn.cursor()
        # return self 如此寫,這個(gè)session必須是一個(gè)線程級(jí)別的,如果用進(jìn)程,則直接覆蓋cursor
        # #因?yàn)榫€程是順序執(zhí)行的,都用新的cursor()當(dāng)查詢數(shù)據(jù)時(shí),數(shù)據(jù)找不到了,因?yàn)閏ursor變了。本session是在線程內(nèi)執(zhí)行,不能夸線程執(zhí)行

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        if exc_type: # 此處用于定義是否出錯(cuò),若出錯(cuò),則直接返回
            self.conn.rollback()
        else:
            self.conn.commit()

class ModeMetd(type):  # 子類構(gòu)建的時(shí)候?qū)崿F(xiàn)的
    def __new__(cls,name,bases,attrs:dict):  # 此處是在類的定義中進(jìn)行調(diào)用的,
        # 此處的name表示被調(diào)用子類的類名,而對(duì)應(yīng)的字典attrs則表示子類的屬性字典
        # name 類名,attrs類屬性字典
        if '__table__'  not in attrs.keys():
            attrs['__table__']=name   #默認(rèn)添加表名稱為類名稱

        mapping={}  # 方便后面查詢屬性名和字段實(shí)例
        primarykey=[]  # 多個(gè)主鍵的情況下使用,如果使用一個(gè)變量名,則導(dǎo)致后面覆蓋前面
        for k,v in attrs.items():  # k代表的是列名稱,v表示的是子類的類型
            if isinstance(v,Field):  # 此處判斷是否繼承與父類
                mapping[k]=v
                if  v.name is None:
                    v.name=k  # 如果是,則將類.name
                if  v.column is None:
                    v.column=v.name # 沒(méi)有給字段名,則使用類對(duì)應(yīng)的列名稱
                if v.pk:
                    primarykey.append(v)
        # 增加屬性
        attrs['__mapping__']=mapping
        attrs['__primarykey__']=primarykey
        return super().__new__(cls,name,bases,attrs)

class  Model(metaclass=ModeMetd):  # 實(shí)體類的調(diào)用時(shí)實(shí)現(xiàn),子類的實(shí)例調(diào)用時(shí)實(shí)現(xiàn)的
    pass

class  Login(Model):
    id=IntField(pk=True,nullable=False,auto_increment=True)
    name=StringField(length=64,nullable=False)
    age=IntField()
    __table__='Login'
    def  __init__(self,id,name,age):
        self.id=id
        self.name=name
        self.age=age
    def __str__(self):
        return   "Loin({},{},{})".format(self.id,self.name,self.age)
    __repr__=__str__
class  Engine:
    def __init__(self,*args,**kwargs):
        self.conn=pymysql.Connect(*args,**kwargs)
    def save(self, instance:Login):
        names = []
        values = []
        for k, v in instance.__mapping__.items():  # 此處用于獲取實(shí)例的名稱和其對(duì)應(yīng)的值
            # print ('for',k,'---',v)
            if isinstance(v, Field):  # 此處若屬于基類
                if k in instance.__dict__.keys():  # 此處的字段符合
                    names.append(k)
                    values.append(instance.__dict__[k])  # v是一個(gè)Field類型的實(shí)例,是子類和父類的實(shí)例
                    print(instance.__dict__[k])  # 此處是實(shí)例。實(shí)例中的數(shù)字
        # __table__  # 此處在子類中添加
        query = "insert into {} ({}) values ({})".format(instance.__table__, ",".join(names),
                                                         ",".join(["%s"] * len(values)))  # 此處是匹配對(duì)應(yīng)的sql
        print(query)
        print (values)

l=Login(1,'admin',20)
e=Engine('192.168.1.120','root','666666','test')
e.save(l)

基礎(chǔ)結(jié)果如下

ORM對(duì)象關(guān)系映射框架基本搭建

#!/usr/bin/poython3.6
#conding:utf-8
import  pymysql
class  Field:
    def __init__(self,name,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        self.name=name  # 字段名稱
        if  column  is None:  #列名稱
            self.column=self.name
        else:
            self.column=column
        self.pk=pk  # 主鍵
        self.unique=unique  #唯一
        self.index=index #索引
        self.nullable=nullable  #是否為空
        self.default=default  # 默認(rèn)是否為空
    def  validate(self,value):  # 此處定義數(shù)據(jù)校驗(yàn)方式,每種不同類型的校驗(yàn)方式不同,因此應(yīng)該在子類中分別實(shí)現(xiàn)
        raise  NotImplementedError  #基類不實(shí)現(xiàn)此功能

    def __get__(self, instance, owner): #此處用于定義描述器,此處當(dāng)子類的類調(diào)用此屬性時(shí),會(huì)返回對(duì)應(yīng)的值
        # 此處的self表示父類的實(shí)例,instance表示子類的實(shí)例,owner表示子類的類
        # pass
        if instance is None:  #此處為None表示子類未生成對(duì)應(yīng)實(shí)例
            return self  # 此處的self表示實(shí)例自己
        return  instance.__dict__[self.name]  # 返回實(shí)例對(duì)應(yīng)的字段名稱
    def __set__(self, instance, value): #此處用于定義數(shù)據(jù)描述器,用于子類實(shí)例調(diào)用時(shí)使用,用于返回對(duì)應(yīng)的結(jié)果
        # instace 表示子類的實(shí)例,其相關(guān)的信息應(yīng)該被存儲(chǔ)于子類實(shí)例中,
        self.validate(value)
        instance.__dict__[self.name]=value #此處的name是字段名,value是子類的self,對(duì)應(yīng)的屬性的值,及真實(shí)的數(shù)據(jù)

    def  __str__(self):
        return   "{} <{}>".format(self.__class__.__name__,self.name)  # 此處返回被調(diào)用的類名和實(shí)例名稱
    __repr__=__str__
# 定義整數(shù)類型的類型屬性
class  IntField(Field):  #多了自增屬性。
    def  __init__(self,name=None,column=None,pk=False,unique=False,index=False,nullable=True,default=None,auto_increment=True):
        self.auto_increment=auto_increment
        super().__init__(name,column,pk,unique,index,nullable,default)

    def validate(self,value):
        if value is  None:
            if self.pk:  # 主鍵不能為空,因此此處會(huì)報(bào)錯(cuò)
                raise TypeError("{}:{}".format(self.name,value))
            if not self.nullable:  # 當(dāng)定義了非空時(shí),上述的值為空,則報(bào)錯(cuò)
                raise TypeError
        else:
            if not isinstance(value,int):  #若數(shù)據(jù)的類型為非int,則報(bào)錯(cuò)
                raise TypeError("{}  is  not  int,  It's {}".format(self.name,type(value)))

# 定義字符串的類型屬性
class  StringField(Field):  #定義字符串屬性類
    # 增加了字符串長(zhǎng)度的定義
    def __init__(self,length=32,name=None,column=None,pk=False,unique=False,index=False,nullable=True,default=None):
        super().__init__(name,column,pk,unique,index,nullable,default)  #此處的屬性可以繼承父類的屬性
        self.length=length  #此處用于定義字符串類型的長(zhǎng)度
    def  validate(self,value):  #此處用于定義各自的屬性檢查,對(duì)數(shù)據(jù)進(jìn)行屬性檢查
        if  value  is None: # 此處的None對(duì)應(yīng)數(shù)據(jù)庫(kù)的null
            if self.pk:  # 如果數(shù)據(jù)是None,而其定義了主鍵,則會(huì)報(bào)錯(cuò),因?yàn)橹麈I必須不能是Null,主鍵非空且唯一
                raise TypeError("{} is pk,not None".format(self.name))
            if not  self.nullable:  # 如果其是None,而定義的是非null,則會(huì)報(bào)錯(cuò)
                raise TypeError("{}  is  not  null".format(self.name))
        else:
            if not isinstance(value,str):
                raise TypeError("{} should be string".format(self.name))
            if len(value) > self.length:  #真實(shí)的值大于規(guī)定的值,則會(huì)報(bào)錯(cuò)
                raise ValueError("{} is to long value={}".format(self.name,value))

# 具體類的實(shí)現(xiàn)
class  Session:  #此處用以封裝鏈接,可在此處增加上下文支持
    def __init__(self,conn:pymysql.connections.Connection):
        self.conn=conn
        self.cursor=None

    def execute(self,query,*args):
        if self.cursor is None:
            self.cursor=self.conn.cursor()
        self.cursor.execute(query,*args)
    def __enter__(self): # 此處實(shí)現(xiàn)方式和
        return self.conn.cursor()
        # self.cursor=self.conn.cursor()
        # return self 如此寫,這個(gè)session必須是一個(gè)線程級(jí)別的,如果用進(jìn)程,則直接覆蓋cursor
        # 因?yàn)榫€程是順序執(zhí)行的,都用新的cursor()當(dāng)查詢數(shù)據(jù)時(shí),數(shù)據(jù)找不到了,因?yàn)閏ursor變了。本session是在線程內(nèi)執(zhí)行,不能夸線程執(zhí)行
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        if exc_type: # 此處用于定義是否出錯(cuò),若出錯(cuò),則直接返回
            self.conn.rollback()
        else:
            self.conn.commit()

class ModeMetd(type):  # 子類構(gòu)建的時(shí)候?qū)崿F(xiàn)的
    def __new__(cls,name,bases,attrs:dict):  # 此處是在類的定義中進(jìn)行調(diào)用的,
        # 此處的name表示被調(diào)用子類的類名,而對(duì)應(yīng)的字典attrs則表示子類的屬性字典
        # name 類名,attrs類屬性字典
        if '__table__'  not in attrs.keys():
            attrs['__table__']=name   #默認(rèn)添加表名稱為類名稱

        mapping={}  # 方便后面查詢屬性名和字段實(shí)例
        primarykey=[]  # 多個(gè)主鍵的情況下使用,如果使用一個(gè)變量名,則導(dǎo)致后面覆蓋前面
        for k,v in attrs.items():  # k代表的是列名稱,v表示的是子類的類型
            if isinstance(v,Field):  # 此處判斷是否繼承與父類
                mapping[k]=v
                if  v.name is None:
                    v.name=k  # 如果是,則將類.name
                if  v.column is None:
                    v.column=v.name # 沒(méi)有給字段名,則使用類對(duì)應(yīng)的列名稱
                if v.pk:
                    primarykey.append(v)
        # 增加屬性
        attrs['__mapping__']=mapping
        attrs['__primarykey__']=primarykey
        return super().__new__(cls,name,bases,attrs)

class  Model(metaclass=ModeMetd):  # 實(shí)體類的調(diào)用時(shí)實(shí)現(xiàn),子類的實(shí)例調(diào)用時(shí)實(shí)現(xiàn)的
    pass

class  Login(Model):
    id=IntField(pk=True,nullable=False,auto_increment=True)
    name=StringField(length=64,nullable=False)
    age=IntField()
    __table__='login'
    def  __init__(self,id,name,age):
        self.id=id
        self.name=name
        self.age=age
    def __str__(self):
        return   "Loin({},{},{})".format(self.id,self.name,self.age)
    __repr__=__str__
class  Engine:
    def __init__(self,*args,**kwargs):
        self.conn=pymysql.connections.Connection(*args,**kwargs)
    def save(self, instance:Login):
        names = []
        values = []
        for k, v in instance.__mapping__.items():  # 此處用于獲取實(shí)例的名稱和其對(duì)應(yīng)的值
            # print ('for',k,'---',v)
            if isinstance(v, Field):  # 此處若屬于基類
                if k in instance.__dict__.keys():  # 此處的字段符合
                    names.append(k)
                    values.append(instance.__dict__[k])  # v是一個(gè)Field類型的實(shí)例,是子類和父類的實(shí)例
        # __table__  # 此處在子類中添加
        query = "insert into {}({}) values({})".format(instance.__table__, ",".join(names),
                                                         ",".join(["%s"] * len(values)))  # 此處是匹配對(duì)應(yīng)的sql
        S=Session(self.conn)
        with  S:
            S.execute(query,values)

e=Engine('192.168.1.200','root','Admin@Root123','test')
for  i in range(10):
    e.save(Login(i,'admin'+str(i),20+i))

結(jié)果如下

ORM對(duì)象關(guān)系映射框架基本搭建

網(wǎng)站欄目:ORM對(duì)象關(guān)系映射框架基本搭建
轉(zhuǎn)載來(lái)源:http://chinadenli.net/article34/giegpe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營(yíng)銷、標(biāo)簽優(yōu)化定制網(wǎng)站、做網(wǎng)站、企業(yè)建站、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司