ORM
ORM
ORM(ObjectRelationMapping):对象关系映射
映射到数据库MySQL中的数据表
类名——>表名
对象——>一条记录
对象.属性——>字段
模拟Django的ORM,是为了将对数据库中的增、删、改、查操作封装成一个个方式,方便调用
ORM处理的事情:
1、控制表类的创建 ---> 控制表创建的过程; 2、给表类封装 增、查、改 方法
# 定义字段类型:每一个字段都应该有:字段名,字段类型,主键,默认值
# 字段父类
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 IntegerField(Field):
# 字段类型默认是int,主键默认是False,默认值默认是0
def __init__(self, name, column_type='int', primary_key=False, default=0):
super().__init__(name, column_type, primary_key, default)
# 字符类型字段
class StringField(Field):
# 字段类型默认是varchar,主键默认False,默认值是None
def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
super().__init__(name, column_type, primary_key, default)
# 自定义元类:解决三件事:
# 1、保证一张表必须有一个表名
# 2、一张表有且只有一个主键
# 3、将所有的 “ 字段名” 和 “字段对象” 添加到一个名称空间中,方便调用(mapping)
class OrmMetaClass(type):
# 由__call__ 产生 __new__ ,定义类就会触发__new__,重新__new__对定义的类进行限制
def __new__(cls, class_name, class_bases, class_dict):
# 不要限制父类Models,过滤掉父类
if class_name == 'Models':
return type.__new__(cls, class_name, class_bases, class_dict)
# 获取table 表名,如果没有,设置默认值为类名
table_name = class_dict.get('table_name', class_name)
# 设置主键变量初始值为None
primary_key = None
# 设置一个空字典用来存放字段和字段对象
mapping = {}
# 循环取值名称空间中的key和value
for key, value in class_dict.items():
# 判断当前的value是否是字段对象
if isinstance(value, Field):
# 将所有的字段和字段对象加入空字典中
mapping[key] = value
# 判断是否有主键,如果有,将primary_key变量赋值
if value.primary_key:
# 第二次进来,如果有主键了,抛出异常
if primary_key:
raise TypeError('只能有一个主键!!!')
primary_key = value.primary_key
# 过滤掉重复的字段属性,节省空间
for key in mapping.keys():
class_dict.pop(key)
# 判断 是否有主键,如果没有,抛出异常
if not primary_key:
raise TypeError('必须要有一个主键!!!')
# 给类的名称空间中加入table_name, primary_key, mapping
class_dict['table_name'] = table_name
class_dict['primary_key'] = primary_key
class_dict['mapping'] = mapping
# 将限制操作后的__new__返回
return type.__new__(cls, class_name, class_bases, class_dict)
# 定义父类
class Models(dict,metaclass=OrmMetaClass):
# 通过对象.属性的方式获取值时,属性没有时调用
def __getattr__(self, item):
return self.get(item)
# 设置对象.属性 = 属性值 时触发
def __setattr__(self, key, value):
self[key] = value
class User(Models):
# 字段类中的name属性,必须要与User表中类属性同名
id = IntegerField(name='id', primary_key=True)
username = StringField(name='username')
password = StringField(name='password')