ORM: Object Relational Mapping---对象关系映射
类名---表名, 一个对象的某个属性值---某个记录, 一个对象的属性值---一条记录, 对象.属性---字段
- 存储对象 --> dict --> Json --> Mysql
- Mysql --> Jason --> dict --> 获取对象
- 一个对象中的所有属性名和属性值映射成一个字典中的keys和values
- 将映射字典序列化成json格式
- 将json格式数据编码传输到服务器
- 在服务器将二进制数据解码并反序列化存入mysql数据库中
自定义元类
'''
自定义元类:
继承type类, 重写__new__方法, 控制类在创建时自动对类的名称空间中的属性进行相应的操作, 包括:
1. 一个表类的名称空间中必须要有一个表名的属性---模型表类除外
2. 一个表类的名称空间中的所有字段属性中, 必须有且仅有一个字段的主键为True
3. 将一个表类的名称空间中的所有字段属性放入一个独立字典中, 与名称空间中的其他属性区分开,
从而方便获取字段属性的属性名, 因其与字段对象中的字段名同名, 故等价于方便了字段名的获取
'''
# 自定义元类
class OrmMeta(type):
# 参数"mcs"为自定义的元类, 由"msc"来创建一个空类
def __new__(mcs, cls_name, cls_bases, cls_dic):
# 过滤掉"TableModel"类, 将其正常创建
if cls_name == 'TableModel':
return type.__new__(mcs, cls_name, cls_bases, cls_dic)
# 保证一个表必定有一个表名
table_name = cls_dic.get('table_name')
if not table_name:
cls_dic['table_name'] = cls_name
# 定义一个字典存储一个表类中的所有字段对象
field_obj_dic = {}
# 保证有且仅有一个主键
count = 0
for key, value in cls_dic.items(): # 遍历表类的名称空间
if isinstance(value, FieldBase): # 过滤掉非字段对象的数据
field_obj_dic[key] = value # 添加字段对象至字典
if value.primary_key: # 判断主键是否存在
primary_key_name = key # 记录主键的字段名
count += 1 # 对主键总数计数
if count > 1:
raise TypeError('只能有一个主键值!') # 主键个数大于1报错
if count == 0:
key = list(field_obj_dic)[0]
primary_key_name = field_obj_dic.get(key).field_name # 没有主键默认将第一个字段名设为主键
# 剔除类的名称空间中的字段对象数据, 节省内存空间
for key in field_obj_dic.keys():
cls_dic.pop(key)
# 给类的名称空间添加主键
cls_dic['primary_key_name'] = primary_key_name
# 给类的名称空间添加包含一个表中的所有字段对象的字典
cls_dic['field_obj_dic'] = field_obj_dic
return type.__new__(mcs, cls_name, cls_bases, cls_dic)
定义表模型类
# 定义表模型类
class TableModel(dict, metaclass=OrmMeta):
# 通过"对象.属性名 = 属性值"的方式往字典对象中存储数据
def __setattr__(self, key, value):
self[key] = value
# 通过"对象.属性名"的方式从字典对象中获取数据
def __getattr__(self, item):
return self.get(item)
# 创建用户表类, 每个字段属性组合对应的字段对象
class UserTable(TableModel):
# 表名
table_name = 'user_info'
# 每个字段属性
user_id = IntegerField('user_id', primary_key=True)
user_name = StringField('user_name')
user_pwd = StringField('user_pwd')
# 创建电影表类
class MovieTable(TableModel):
movie_id = IntegerField('movie_id', primary_key=True)
movie_name = StringField('movie_name')
movie_pwd = StringField('movie_pwd')
user1 = UserTable(user_id=1, user_name='tank', user_pwd='123')
print(UserTable.__dict__)