ORM簡介 ORM即Object Relational Mapping,全稱對象關係映射。當我們需要對資料庫進行操作時,勢必需要通過連接數據、調用sql語句、執行sql語句等操作,ORM將資料庫中的表,欄位,行與我們面向對象編程的類及其方法,屬性等一一對應,即將該部分操作封裝起來,程式猿不需懂得sq ...
ORM簡介
ORM即Object Relational Mapping,全稱對象關係映射。
當我們需要對資料庫進行操作時,勢必需要通過連接數據、調用sql語句、執行sql語句等操作,ORM將資料庫中的表,欄位,行與我們面向對象編程的類及其方法,屬性等一一對應,即將該部分操作封裝起來,程式猿不需懂得sql語句即可完成對資料庫的操作。
一、知識儲備:
1、在實例化一個user對象的時候,可以user=User(name='lqz',password='123')
2 也可以 user=User()
user['name']='lqz'
user['password']='123'
3 也可以 user=User()
user.name='lqz'
user.password='password'
前兩種,可以通過繼承字典dict來實現,第三種,用getattr和setattr:
__getattr__ 攔截點號運算。當對未定義的屬性名稱和實例進行點號運算時,就會用屬性名作為字元串調用這個方法。如果繼承樹可以找到該屬性,則不調用此方法
__setattr__會攔截所有屬性的的賦值語句。如果定義了這個方法,self.arrt = value 就會變成self,__setattr__("attr", value).這個需要註意。當在__setattr__方法內對屬性進行賦值是,不可使用self.attr = value,因為他會再次調用self,__setattr__("attr", value),則會形成無窮遞歸迴圈,最後導致堆棧溢出異常。應該通過對屬性字典做索引運算來賦值任何實例屬性,也就是使用self.__dict__['name'] = value
二、定義Model基類
# 在ModelsMetaclass中自定義攔截實例化對象的方法 class Models(dict,metaclass=ModelsMetaclass): # k,v形式的值 def __init__(self,**kwargs): super().__init__(**kwargs) # 寫存 def __setattr__(self, key, value): self[key] = value # 讀取 def __getattr__(self, item): try: return self[item] except KeyError: raise ('沒有該屬性')
三、定義Field
資料庫中每一列數據,都有:列名,列的數據類型,是否是主鍵,預設值
# 表示一個列:列名,列的類型,列的主鍵和預設值 class Field: def __init__(self,name,column_type,primary_key,default): self.name = name self.column_type = column_type self.primary_key = primary_key self.default = default class StringField(Field): def __init__(self,name=None,column_type='varchar(200)',primary_key=False,default=None): super().__init__(name,column_type,primary_key,default) class IntegerField(Field): def __init__(self,name=None,column_type='int',primary_key=False,default=None): super().__init__(name,column_type,primary_key,default)
四、定義元類
資料庫中的每個表,都有表名,每一列的列名,以及主鍵是哪一列
既然我要用資料庫中的表,對應這一個程式中的類,那麼我這個類也應該有這些類屬性
但是不同的類這些類屬性又不盡相同,所以我應該怎麼做?在元類里攔截類的創建過程,然後把這些東西取出來,放到類裡面
class ModelsMetaclass(type): def __new__(cls,name,bases,attrs): if name == 'Models': # return type.__new__(cls, name, bases, attrs) table_name = attrs.get('table_name', None) #字典取值,中括弧或.get if not table_name: table_name = name primary_key = None mappings = dict() for k, v in attrs.items(): if isinstance(v, Field): # v 是不是Field的對象 mappings[k] = v if v.primary_key: # v是基類對象,即判斷該欄位的主鍵 # 找到主鍵 if primary_key: raise TypeError('主鍵重覆:%s' % k) primary_key = k for k in mappings.keys(): attrs.pop(k) # 執行完此步後,attrs中只剩餘有__屬性__ if not primary_key: raise TypeError('沒有主鍵') attrs['table_name'] = table_name attrs['primary_key'] = primary_key attrs['mappings'] = mappings return type.__new__(cls, name, bases, attrs)
五、基於pymysql的資料庫操作類(單例)
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/05/15 10:44 # @Author : MJay_Lee # @File : mysql_singleton.py # @Contact : [email protected] import pymysql class Mysql_interface: __instense = None def __init__(self): self.conn = pymysql.connect( host = '127.0.0.1', port = 3306, user = 'root', password = '123456', charset = 'utf8', database = 'youku', autocommit = True ) self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def close_db(self): self.cursor.close() self.conn.close() def select(self,sql,args): self.cursor.execute(sql,args) re = self.cursor.fetchall() return re def execute(self,sql,args): try: self.cursor.execute(sql,args) affected = self.cursor.rowcount except BaseException as e: print(e) return affected @classmethod def singleton(cls): if not cls.__instense: cls.__instense = cls() return cls.__instense if __name__ == '__main__': ms = Mysql_interface() re = ms.select('select * from user where id = %s',1) print(re)
六、繼續Models基類
Models類是所有要對應資料庫表類的基類,所以,Models的元類應該是咱們上面寫的那個
而每個資料庫表對應類的對象,都應該有查詢、插入、保存,方法
所以:
# 在ModelsMetaclass中自定義攔截實例化對象的方法 class Models(dict,metaclass=ModelsMetaclass): # k,v形式的值 def __init__(self,**kwargs): super().__init__(**kwargs) # 寫存 def __setattr__(self, key, value): self[key] = value # 讀取 def __getattr__(self, item): try: return self[item] except KeyError: raise ('沒有該屬性') @classmethod def select_one(cls,**kwargs): # 只查一條 key = list(kwargs.keys())[0] value = kwargs[key] # select * from user where id=%s sql = 'select * from %s where %s =?' % (cls.table_name,key) sql = sql.replace('?','%s') ms = mysql_singleton.Mysql_interface().singleton() re = ms.select(sql,value) # 得到re字典對象 if re: # attrs = {'name':'lmj','password':123} # User(**attrs) # 相當於 User(name='lmj',password=123) return cls(**re[0]) else: return class User(Models): ''' 首先賦值表名 其次根據資料庫表結構來賦值 ''' table_name = 'user' # k v(Field的對象) id = IntegerField('id',primary_key=True,default=0) password = StringField('password') if __name__ == '__main__': # user = User() # user.name = 'name' # user['id'] = 1 # print(user.id) user = User().select_one(id=1) print(user)