ROM框架
ORM对象映射关系
类名 -- 表名
对象 -- 记录
对象.属性 --- 字段
1.定义表字段的类型
2.创建元类,限制表类的创建
'''
元类需要处理的问题:
1.一张表必须要有一个表名。
2.给数据表类,强制必须要有一个主键,主键必须是唯一的。
3.将数据表中,所有的字段对象,都存放在一个独立的字典中
存不是目的,目的是为了取值方便。
'''
-
过滤Models类,models类中,什么都不做,将类原路返回。
-
一张表必须有表名,如果没有则将类名做表名
-
表名 主键名 定义一个空字典,用来存放字段对象
-
-
遍历名称空间的属性判断主键的存在与否
-
节省资源:mappings字典中与原名称空间中有属性重复,提出属性
3.创建用户表类,继承dict与元类,以解决表类中数据的不一致传参,和主键的限制
'''
ORM对象映射关系
类名 -- 表名
对象 -- 记录
对象.属性 --- 字段
'''
# 1.创建字段的类型
# 创建字段时,create table id int primary key default
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
# 创建int类型
class IntegerField(Field):
def __init__(self,name,column_type='int',primary_key=False,default=0):
super().__init__(name,column_type,primary_key,default)
# 创建str类型
class StringField(Field):
def __init__(self,name,column_type='varchar(64)',primary_key=False,default=None):
super().__init__(name,column_type,primary_key,default)
'''
元类需要处理的问题:
1.一张表必须要有一个表名。
2.给数据表类,强制必须要有一个主键,主键必须是唯一的。
3.将数据表中,所有的字段对象,都存放在一个独立的字典中
存不是目的,目的是为了取值方便。
'''
# 2.创建元类并限制表类的创建条件
class Mymetaclass(type):
def __new__(cls,class_name,class_base,class_dict):
# print(class_name) # 类名
# print(class_base) # 父类
# print(class_dict) # 类的名称空间(属性)
if class_name == 'Models':
# models类中,什么都不做,将类原路返回。
return type.__new__(cls, class_name, class_base, class_dict)
# 1.表名
table_name = class_dict.get('table_name',class_name)
# 2.主键名
key = None
# 3.定义一个空字典,用来存放字段对象
mappings = {}
# 遍历名称空间中的所有属性
for k ,v in class_dict.items():
# print(k,v) # 除了有字段,还有其他字段以外的属性
'''
__module__ __main__
__qualname__ User
user_id <__main__.IntegerField object at 0x00000173FF5CFD30>
user_name <__main__.StringField object at 0x00000173FF5CFCF8>
pwd <__main__.StringField object at 0x00000173FF5CFCC0>'''
# 过滤字段对象以外的内容
if isinstance(v,Field):
mappings[k] = v # 保存至字段字典中
# print(k,v)
'''user_id <__main__.IntegerField object at 0x0000020CDCDAFD30>
user_name <__main__.StringField object at 0x0000020CDCDAFCC0>
pwd <__main__.StringField object at 0x0000020CDCDAFCF8>'''
# print(mappings)
'''{'user_id': <__main__.IntegerField object at 0x00000212F5BFFD30>}
{'user_id': <__main__.IntegerField object at 0x00000212F5BFFD30>, 'user_name': <__main__.StringField object at 0x00000212F5BFFCF8>}
{'user_id': <__main__.IntegerField object at 0x00000212F5BFFD30>, 'user_name': <__main__.StringField object at 0x00000212F5BFFCF8>, 'pwd': <__main__.StringField object at 0x00000212F5BFFCC0>}'''
# 判断字段对象primary_key是否为True,然后再判断设置的key有没有值
if v.primary_key:
# 再判断初始的key是否有值
if key:
# 如果有值代表有两个主键
raise TypeError('只能有一个主键')
# 若对象字段主键不存在,则给key赋值,说明主键字段有值了
key = v.name
# print(v.name) # user_id
# 判断是否有主键
if not key:
raise TypeError('必须有一个主键')
#
# # 判断是否有主键
# if not key:
# raise TypeError('必须有一个主键')
# 节省资源:mappings字典中与原名称空间中有属性重复,提出属性
for k in mappings.keys(): # 遍历所有的keys,去除class_dict 中的相同值
class_dict.pop(k) # pop 删除dict中对应k的键值对
print(class_dict)
'''{'__module__': '__main__', '__qualname__': 'User'}'''
# 给类的名称空间添加表名
class_dict['table_name'] = table_name
# 给类的名称空间添加主键名
class_dict['primary_key'] = key
# 给类的名称空间添加一个mappings字典,字典拥有所有字段属性
class_dict['mappings'] = mappings
# print(class_dict)
'''
{'__module__': '__main__', '__qualname__': 'User', 'table_name': 'User', 'primary_key': 'user_id', 'mappings': {'user_id': <__main__.IntegerField object at 0x000001D5393DFD30>, 'user_name': <__main__.StringField object at 0x000001D5393DFCC0>, 'pwd': <__main__.StringField object at 0x000001D5393DFCF8>}}'''
# 返回__new__创建的对象
return type.__new__(cls,class_name,class_base,class_dict)
# 3.创建用户表类,继承dict与元类,以解决表类中数据的不一致传参,和主键的限制
class Models(dict,metaclass=Mymetaclass):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
# 用户表
class User(Models):
# 类名就是表名,类的属性(对象)就是字段.
user_id = IntegerField(name='user_id',primary_key=True)
user_name = StringField(name='user_name')
pwd = StringField('pwd')
pass
if __name__ == '__main__':
User()
# print(User.__dict__)
model中定义 查找,插入,更新,删除的方法
'''
ORM对象映射关系
类名 -- 表名
对象 -- 记录
对象.属性 --- 字段
'''
from MySQL_control import MySQL
# 1.创建字段的类型
# 创建字段时,create table id int primary key default
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
# 创建int类型
class IntegerField(Field):
def __init__(self,name,column_type='int',primary_key=False,default=0):
super().__init__(name,column_type,primary_key,default)
# 创建str类型
class StringField(Field):
def __init__(self,name,column_type='varchar(64)',primary_key=False,default=None):
super().__init__(name,column_type,primary_key,default)
'''
元类需要处理的问题:
1.一张表必须要有一个表名。
2.给数据表类,强制必须要有一个主键,主键必须是唯一的。
3.将数据表中,所有的字段对象,都存放在一个独立的字典中
存不是目的,目的是为了取值方便。
'''
# 2.创建元类并限制表类的创建条件
class Mymetaclass(type):
def __new__(cls,class_name,class_base,class_dict):
# print(class_name) # 类名
# print(class_base) # 父类
# print(class_dict) # 类的名称空间(属性)
if class_name == 'Models':
# models类中,什么都不做,将类原路返回。
return type.__new__(cls, class_name, class_base, class_dict)
# 1.表名
table_name = class_dict.get('table_name',class_name)
# 2.主键名
primary_key = None
# 3.定义一个空字典,用来存放字段对象
mappings = {}
# 遍历名称空间中的所有属性
for k ,v in class_dict.items():
# print(k,v) # 除了有字段,还有其他字段以外的属性
# 过滤字段对象以外的内容
if isinstance(v,Field):
mappings[k] = v # 保存至字段字典中
# print(k,v)
# print(mappings)
# 判断字段对象primary_key是否为True,然后再判断设置的key有没有值
if v.primary_key:
# 再判断初始的key是否有值
if primary_key:
# 如果有值代表有两个主键
raise TypeError('只能有一个主键')
# 若对象字段主键不存在,则给key赋值,说明主键字段有值了
key = v.name
# print(v.name)
# # 判断是否有主键
# if not primary_key:
# raise TypeError('必须有一个主键')
# 节省资源:mappings字典中与原名称空间中有属性重复,提出属性
for k in mappings.keys(): # 遍历所有的keys,去除class_dict 中的相同值
class_dict.pop(k) # pop 删除dict中对应k的键值对
# print(class_dict)
# 判断是否有主键
if not primary_key:
raise TypeError('必须有一个主键')
# 给类的名称空间添加表名
class_dict['table_name'] = table_name
# 给类的名称空间添加主键名
class_dict['primary_key'] = primary_key
# 给类的名称空间添加一个mappings字典,字典拥有所有字段属性
class_dict['mappings'] = mappings
# print(class_dict)
# 返回__new__创建的对象
return type.__new__(cls,class_name,class_base,class_dict)
# 3.创建用户表类,继承dict与元类,以解决表类中数据的不一致传参,和主键的限制
class Models(dict,metaclass=Mymetaclass):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
# 查找,插入,更新,删除的方法
# 查找 (将查询封装为类方法,由类直接调用查找)
@classmethod
def select(cls,**kwargs): # 利用**kwargs打散关键字参数为字典
# print(kwargs)
# 调用Mysql拿到对象 mysql
mysql = MySQL()
# 查询指令有全部查询,与按条件where查询
# 1.sql = 'select * from table;'
if not kwargs: # 如果没有where 条件的指令走这里
sql = 'select * from %s ' % cls.table_name # 通过类方法获得类名
res = mysql.my_select(sql) # 调用client的select方法
else: # 有值的话证明需要where 条件查询
# 2.sql = 'select * from table where 条件;'
key = list(kwargs.keys())[0] #获取传入的参数(list类型转换为列表)取值
# print(list(kwargs.keys()))
value = kwargs.get(key) # 按key取值获取传入的value
# 查询的条件语句
sql = 'select * from %s where %s=? ' % (cls.table_name,key)
# 使用%s 替换?, ? 的作用是防止用户输入时的sql注入
sql = sql.replace('?','%s')
# 拿到mysql的游标,提交sql语句
res = mysql.my_select(sql,value)
# d = {'id':1,'name':2} ** 可以将字典打散传入函数中为关键字参数
return [cls(**d) for d in res] #return出去的就具有.属性的方法取值
# 插入 User(传关键字参数) ---》 user_obj.insert(user_obj)
def insert(self): # 对象调用传入参数,用户输入的是值,字段名设置好的
# 调用mysql 拿到对象
mysql = MySQL()
# insert into table (字段名) values (值);
# 其中 字段可能有多个值,传值也有多个,所以用%s进行替代
# 存储所有的字段名
keys = []
# 存字段对应的值
values = []
# 存放?号的,有几个字段,就存在几个?号,替换条件'???'
args = []
# mappings存放的是字段的对象,通过items 循环取出
for k,v in self.mappings.items():
# print(k,v) # user_id = IntegerField(name='user_id',primary_key=True)
# 过滤掉主键,因为主键是自增的,不需要添加
if not v.primary_key:
# 存表中除了主键以外的字段名
keys.append(v.name) # k == v.name
# 存表中除了主键以外的字段值,若值没有,则使用默认值
values.append( getattr(self , v.name , v.default) ) # 通过反射才能找到传的值
# 这里values获取的是用户传来的所有关键字参数的值,也就是修改的值.
# 存放?号,有几个字段,就存几个?号,用来替换用户输入的字符
args.append('?')
# print(keys)
# print(values)
# print(args)
# sql: insert into table_name(v1, v2, v3) values(?, ?, ?)
sql = 'insert into %s(%s) values (%s);' % (
self.table_name,
','.join(keys),
','.join(args)
)
sql = sql.replace('?','%s')
# sql: insert into table_name(v1, v2, v3) values(%s, %s, %s)
# 封装一个my_execupt方法,用于发送指令
mysql.my_execupt(sql,values)
# mysql.cursor.execute(sql, values)
# 更新
def sql_update(self):
# 默认使用主键当做更新的查询条件 primary_key的名字是主键名,主键
mysql = MySQL()
# 字段名
keys = []
# 字段值
values = []
# 主键 id = pk --- id = 1 这样的
primary_key = None # 主键可能不一样,所以需要主键名
# 获取所有的字段名以及字段的对象
for k,v in self.mappings.items():
# 判断如果是主键的话进行赋值操作
if v.primary_key:
# 定义拼接主键为: 具有主键的名(id) + '=' + 利用反射id获取的主键的对应值
primary_key = v.name + '=%s' % getattr(self,v.name)
print(v.name)
print(getattr(self,v.name))
# 其他的都是需要修改的值(除了主键剩下的都是字段了)
else:
# 获取所有的字段的名字
keys.append(v.name + '=?') # ? 则是用户输入的值,传值时需要替换,再传入values
# 通过getattr 反射获得所有字段的值
values.append(getattr(self,v.name))
# sql: update table set k1=?, k2=? where id=pk; #
# sql = update table set key=value, k2=v2 where user_id = 1;(这里将主键固定为条件)
# 将where 条件后的'主键字段=主键值' 替换为一个 %s
sql = 'update %s set %s where %s' % (
self.table_name,
','.join(keys),
primary_key
)
# 替换"?"
sql = sql.replace('?','%s')
# 调用mysql中的my_execupt上传方法
mysql.my_execupt(sql,values)
# 用户表
class User(Models):
# 类名就是表名,类的属性(对象)就是字段.
user_id = IntegerField(name='user_id',primary_key=True)
user_name = StringField(name='user_name')
pwd = StringField('pwd')
pass
if __name__ == '__main__':
# 增 orm_insert
# User表 ---> 添加字段对应的数据
obj = User(user_name='小明', pwd='123')
obj.insert()
# 查询
# res1 = User.select() # 查询所有
# print(1,res1)
# res2 = User.select(user_name='小明')
# print(2,res2)
# 改
# obj = User.select()
# print(obj.user_name)
# obj.user_name = '小红'
# obj.sql_update()