Python實現一個ORM模型類

  • 2020 年 3 月 26 日
  • 筆記

ORM是三個單詞首字母組合而成,包含了Object(對象-類),Relations(關係),Mapping(映射)。解釋過字面意思,但ORM的概念仍然模糊。私以為要理解一個事物,最好的法子是搞明白它出現是為了解決什麼問題。

一個簡單的ORM模型

我們也可以通過元類來實現自己的ORM。下面將涉及兩個知識點:元類,描述符。

首先完成屬性描述符的設計:

class BaseFiled(object):      pass      class CharFiled(BaseFiled):      def __init__(self, max_len=10):          self.max_len = max_len        def __get__(self, instance, owner):          return self.value        def __set__(self, instance, value):          if isinstance(value, str):              # 判斷類型進行控制              if len(value) <= self.max_len:                  self.value = value              else:                  raise TypeError('超出最大長度')          else:              raise TypeError('need a str')        def __delete__(self, instance):          self.value = None      class IntFiled(BaseFiled):      def __init__(self, max_len=10):          self.max_len = max_len        def __get__(self, instance, owner):          return self.value        def __set__(self, instance, value):          if isinstance(value, int):              # 判斷類型進行控制              if len(str(value)) <= self.max_len:                  self.value = value              else:                  raise TypeError('超出最大長度')          else:              raise TypeError('need a int')        def __delete__(self, instance):          self.value = None      class BoolFiled(BaseFiled):      def __init__(self, max_len=10):          self.max_len = max_len        def __get__(self, instance, owner):          return self.value        def __set__(self, instance, value):          if isinstance(value, bool):              # 判斷類型進行控制              self.value = value          else:              raise TypeError('need a bool')

實現一個元類:

class FieldMetaClass(type):      # 創建模型類的元類      def __new__(cls, name, bases, dic, *args, **kwargs):          if name == 'BaseModel':              return super().__new__(cls, name, bases, dic)          table_name = name.lower()          # 將類名轉換成小寫,對應數據表的名稱          fields = {}          for k, v in dic.items():              # 判斷value的類型是不是BaseFiled類型的 因為調用的類的父類就是BaseFiled 所以通過CharFiled等創建出來的對象也就是BaseFiled類型的              if isinstance(v, BaseFiled):                  fields[k] = v          dic['t_name'] = table_name          dic['fields'] = fields          # 將類名和屬性取出來放在一個字典中          return super().__new__(cls, name, bases, dic)

給模型類創建一個父類,具體原因及作用可以觀察注釋:

class BaseModel(metaclass=FieldMetaClass):      # 模型類的父類      def __init__(self, **kwargs):          # kwargs 傳入的是一個字典          for k, v in kwargs.items():              setattr(self, k, v)              # setattr 設置屬性  傳入對象、屬性名、屬性值        def save(self):          # 保存一條數據,生成一條對應的sql語句          # 獲取表名          t_name = self.t_name          # 獲取字段名稱          fields = self.fields          # 獲取對應字段的值          filed_dict = {} # 創建一個字典用來存儲鍵值對          for filed in fields.keys():              value = getattr(self, filed)              # 把遍歷出來的鍵中的值找到              filed_dict[filed] = value            # 生成對應的sql語句          sql = 'INSERT INTO {0} VALUES {1};'.format(t_name, tuple(filed_dict.values()))         

生成模型類:

class User(BaseModel):      # 用戶模型類 在模型類中不會重寫init方法,在它的父類中寫init方法 它會自動繼承      username = CharFiled()      pwd = CharFiled()      age = IntFiled()      live = BoolFiled()

調用方式:

a = User(username='12', pwd='19', age=20, live=True)  a.save()

這樣就實現了一個模型類,注釋寫的個人感覺還是比較清晰的,有不清楚的歡迎留言交流