1. 程式人生 > >Django核心:元類與orm物件關係對映

Django核心:元類與orm物件關係對映

元類

python中所有東西都是物件,包括類也是物件,建立類的類就叫做元類,參考文章深刻理解元類

一個例項
def upper_attr(class_name,class_parents,class_attr):
    new_attr={}
    for name,value in class_attr.items():
        if not name.startswith("__"):
            new_attr[name.upper()]=value

    return type(class_name,class_parents,new_attr)
class Foo(object,metaclass=upper_attr): bar="bip" print(hasattr(Foo,"bar")) print(hasattr(Foo,"BAR")) f=Foo() print(f.BAR)

建立一個類的時候如果沒有metaclass引數,就直接用type建立類,但是有了這個引數之後,去到這個函式引用,把類名Foo傳遞給class_name,把object傳遞給class_parents,把其他類屬性傳遞給class_attr。返回type(class_name,class_parents,class_attr)

面向物件改造
class UpperAttrMetaClass(type):
    def __new__(cls, class_name,class_parents,class_attr):
        new_attr={}
        for name,value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()]=value

        return type(class_name,class_parents,new_attr)
class Foo(object,metaclass=UpperAttrMetaClass):#指定一個元類 bar="bip" print(hasattr(Foo,"bar")) print(hasattr(Foo,"BAR")) f=Foo() print(f.BAR)

以上程式碼實現的是將建立類的屬性都變成大寫

orm本質

其本質是通過呼叫物件實現同等的sql語句

  • ex:insert into 表 欄位列表 value 欄位值列表==> u=user(字典)  u.save()

orm實現

class ModelMetaClass(type):                                                                                       
    def __new__(cls, name, bases, attrs):                                                                         
        mappings = dict()                                                                                         
        for k, v in attrs.items():                                                                                
            if isinstance(v, tuple):                                                                              
                mappings[k] = v                                                                                   
                                                                                                                  
        for k in mappings.keys():                                                                                 
            attrs.pop(k)                                                                                          
                                                                                                                  
        attrs['__mappings__'] = mappings                                                                          
        attrs['__table__'] = name                                                                                 
        return type.__new__(cls,name,bases,attrs)                                                                 
                                                                                                                  
class User(metaclass=ModelMetaClass):                                                                             
    uid=('uid',"int unsigned")                                                                                    
    name=('username',"barchar(30)")                                                                               
    email=('email',"varchar(30)")                                                                                 
    password=('password',"varchar(30)")                                                                           
                                                                                                                  
    def __init__(self,**kwargs):                                                                                  
        for name,value in kwargs.items():                                                                         
            setattr(self,name,value)                                                                              
                                                                                                                  
    def save(self):                                                                                               
            fields=[]                                                                                             
            args=[]                                                                                               
            for k,v in self.__mappings__.items():                                                                 
                fields.append(v[0])                                                                               
                args.append(getattr(self,k,None))                                                                 
                                                                                                                  
            args_temp=list()                                                                                      
            for temp in args:                                                                                     
                if isinstance(temp,int):                                                                          
                    args_temp.append(str(temp))                                                                   
                elif isinstance(temp,str):                                                                        
                    args_temp.append("""'%s'"""%temp)                                                             
                                                                                                                  
            sql='insert into %s (%s) values (%s)'%(self.__table__,','.join(fields),\                              
                                                   ','.join(str(i) for i in args_temp))                           
            print(sql)                                                                                            
                                                                                                                  
u=User(uid=122,name="zhangyue",email="xxx",password="pass")                                                       
                                                                                                                  
u.save()                                                                                                          

思想:
用元類來建立User類,uid、name、email、password等屬性。傳遞到元類,元類接受之後把他們轉換成字典,用__mappings__儲存,表明也就是User用__table__儲存,用pop刪除原來的屬性,使字典為新的屬性,這樣做的目的是為了匹配sql語句的表名,和欄位名


在這裡插入圖片描述#執行結果
在這裡插入圖片描述
author:specyue@mail.ustc.edu.cn
github:https://github.com/zhangyuespec/mini_web