ORM:对象关系映射
用来把对象模型表示的对象映射到基于S Q L 的关系模型数据库结构中去。这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的 SQL 语句打交道,只需简单的操作实体对象的属性和方法 。ORM 技术是在对象和关系之间提供了一条桥梁,前台的对象型数据和数据库中的关系型的数据通过这个桥梁来相互转化 。
ORM模型的简单性简化了数据库查询过程。使用ORM查询工具,用户可以访问期望数据,而不必理解数据库的底层结构。
实现简易版ORM
因为数据库的一张表相当于创建一个类,表内的一条记录相当一个对象,那我们就要实现利用对象的点语法可以取出表内的数据。
这里利用字典k-v键值对的形式存储数据的特点实现对象的点语法取值
首先创建一个类,继承dict类,重写 __ getattr __ ,__ setattr __ 方法实现对象的点语法取值和存值。
class Models(dict):
def __init__(self,**kwargs):
super().__init__(**kwargs)
# __getattr__: 在对象获取它没有的属性和方法的时候自动触发
def __getattr__(self, item):
return self.get(item,'该key不存在!')
# __setattr__: 在对象点属性设置属性值的时候自动触发
def __setattr__(self, key, value):
self[key] = value
res = Models(name='linwow',password=123)
print(res.id)
res['password'] = 456
print('用对象的形式赋值:',res.name)
print('用字典的形式赋值:',res.password)
'''
该key不存在!
用对象的形式赋值: linwow
用字典的形式赋值: 456
'''
表中包含字段名和属性,这里利用类的方式实现 varchar 和 int 两种类型的字段
表的字段通常需要有的属性字段名,字段类型,是否是主键,默认值
class Field(object):
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
定义一个类,可以实例化varchar类型的字段
class Stringfield(Field):
def __init__(self,name,column_type = 'varchar(32)',primary_key = False,default=None):
super().__init__(name,column_type,primary_key,default)
定义一个类,可以实例化varchar类型的字段
class IntegerField(Field):
def __init__(self,name,column_type='int',primary_key=False,default=0):
super().__init__(name,column_type,primary_key,default)
在创建表的时候我们需要对一些字段和属性进行规范,所以利用元类来控制对象的创建。
class MyMetaClass(type):
# 元类被继承是传入的参数为(’类名‘,’类的基类‘,’类的名称空间‘,所以直接用三个形参来接受
def __new__(cls, class_name,class_bases,class_attrs):
# 因为元类是用来拦截模型表的创建过程,而models并不是一张模型表,所以不需要它的创建过程
if class_name =='Models':
return type.__new__(cls,class_name,class_bases,class_attrs)
table_name = class_attrs.get('table_name',class_name)
primary_key = None
# 用来存储自己定义的字段类型的属性
mappings = {
}
# 下面的for循环需要做两件事
# 1.将单个单个的字段整合成一个
# 2.确定当前表当地哪个字段是主键
for k,v in class_attrs.items():
# 拿出所有自己定义的表的字段属性
if isinstance(v,Field):
# 将所有的自己定义的表的字段存入字典中
mappings[k] = v
# 校验一张表不能有多个主键
if v.primary_key:
raise TypeError('一张表只能有一个主键')
primary_key = v.name
# 循环mapping拿到所有的自定义字段名
for k