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()
这样就实现了一个模型类,注释写的个人感觉还是比较清晰的,有不清楚的欢迎留言交流