概要
本文僅僅是對廖雪峯老師的使用元類自定義ORM進行改進,並非要建立一個ORM框架python
編寫field
class Field(object): def __init__(self, column_type,max_length,**kwargs): ''' 1,刪除了參數name,field參數所有爲定義字段類型相關參數,和衆多有名的orm相同 2,使用反射,方便字段的擴展,如本例使用deafault就是反射的應用 ''' self.column_type = column_type #字段類型 self.max_length=max_length #字段長度 self.default=None #字段默認值,若是想擴展能夠填寫更多的參數 if kwargs: for k,v in kwargs.items(): if hasattr(self,k): setattr(self,k,v) def __str__(self): return '<%s>' % (self.__class__.__name__) class StringField(Field): def __init__(self,max_length,**kwargs): super().__init__(column_type='varchar({})'.format(max_length),max_length=max_length,**kwargs) class IntegerField(Field): def __init__(self,**kwargs): super().__init__(column_type='bigint',max_length=8)
編寫metaclass
class ModelMetaclass(type): def __new__(cls, name, bases, attrs): if name=='Model': return type.__new__(cls, name, bases, attrs) mappings = dict() for k, v in attrs.items(): #print('k={},v={}'.format(k,v)) if isinstance(v, Field): mappings[k] = v for k in mappings.keys(): attrs.pop(k) attrs['__mappings__'] = mappings # 保存屬性和列的映射關係 attrs['__table__'] = attrs.get('Meta').table or name # 假設表名和類名一致 return type.__new__(cls, name, bases, attrs)
編寫model
class Model(dict, metaclass=ModelMetaclass): def __init__(self, **kw): super(Model, self).__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value): self[key] = value def save(self): fields = [] params = [] for k, v in self.__mappings__.items(): fields.append(k) params.append(getattr(self, k,v.default)) sql = 'insert into {} ({}) values ({})'.format(self.__table__, self.join(fields) ,self.join(params)) print('SQL: %s' % sql) #本身寫了一個join函數,廖雪峯老師使用自帶join,沒法處理數字等非字符串類型 import functools def join(self,attrs,pattern=','): return functools.reduce(lambda x,y:'{}{}{}'.format(x,pattern,y),attrs)
測試
class User(Model): #使用Meta,能自定義表的相關信息 class Meta: #自定義表名 table='users' # 定義類的屬性到列的映射: id = IntegerField() name = StringField(max_length=50) email = StringField(max_length=50,default='root@123.com') password = StringField(max_length=50) if __name__=="__main__": # 建立一個實例: u=User(id=234,name='jane',password='pwd') # 保存到數據庫: u.save() #打印結果;SQL: insert into users (id,name,email,password) values (234,jane,root@123.com,pwd)
引用
1, 廖雪峯:使用元類git
2, github:本文源碼github