ORM文件
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 class stringfield(field): # 定义一个字符串类 #要定义字段名,类型是varchar,主键为False等着传值,默认值为空 def __init__(self,name,column_type='varchar(255)', primary_key = False,default = None): super().__init__(name,column_type,primary_key,default) class integerfield(field): # 定义一个整型类 # 要定义字段名,类型是int,主键为False等着传值,默认值为空 def __init__(self,name,column_type='int', primary_key=False,default=0): super().__init__(name,column_type,primary_key,default) class ModelMetaClass(type): #类对应的是表,通过元类来使创建类时带有表的各种字段 #通过写一个new方法来控制创建类时创建的属性 def __new__(cls,name,bases,attrs): #我们写元类是为了拦截模型表的创建,而不是models这个方法类的创建 if name == 'Models': #返回一个没加限制的new方法 return type.__new__(cls,name,bases,attrs) table_name = attrs.get('table_name',name) # 获取表名,如果没有那就用类名 primary_key = None mappings = {} for k,v in attrs.items(): # k是表的字段名,v是用字段类型创建的对象 if isinstance(v,field): # 判断是不是我们自己创建的字段,如name,id等 mappings[k] = v # 将我们自己定义的字段放入一个单独的字典里 if v.primary_key: # 判断该字段是否是主键 if primary_key: # 查看主键字段被标识出来没有,如果已经有了就报错 raise TypeError('一张表有且只有一个主键') primary_key = v.name # 如果没有,就将主键的字段名标出来 #将单个的自定义的字段属性从attrs中拿出来 for k in mappings.keys(): attrs.pop(k) # 判断字段有没有主键 if not primary_key: raise TypeError('没有设置主键') # 将表的三个特性就是表名,主键,字段付给类的属性 attrs['table_name'] = table_name attrs['primary_key'] = primary_key attrs['mappings'] = mappings return type.__new__(cls, name, bases, attrs) #定义一个方法类,里面放的是通过点方法修改数据库的函数 #继承了字典的方法,可以接收各种关键字参数并将其实例化 class Models(dict,metaclass=ModelMetaClass): def __init__(self,**kwargs): super().__init__(**kwargs) #表类实例化出来的是一个字典,传入的也是一个字典,字典不能直接点什么属性 #所以我们让字典在点什么的时候触发的__getattr__里返回出字典里放的属性对应的值 #通过点方法来获取字典对象的值 def __getattr__(self,item): return self.get(item,'没有该键对值') #通过点方法修改或增加字典对象的值 def __setattr__(self,key,value): self[key] = value #定义类方法 @classmethod def select(cls,**kwargs): # **kwargs是一个字典 ms = Mysql() #查询有两种可能一种是取所有的数据,另一种是根据条件来查询相对应的数据 #第一种相当于select * from userinfo这样 #第二种相当于select * from userinfo where id=%s这样 #所以我们通过判断kwargs有没有传值来判断是那种查询 if not kwargs: #当kwargs没有被传参时 sql = "select * from %s"%cls.table_name res = ms.select(sql) else: #当kwargs被传值(也就是要根据条件查询时) key = list(kwargs.keys())[0] # 规定过滤条件只有一个,我们只拿一个值 value = kwargs.get(key) # 拿到key对应的值 sql = 'select * from %s where %s=?'%(cls.table_name,key) # %s在这里是为了拼接字段名,但字段值也需要拼接,所以我们先用?代替 sql = sql.replace('?','%s') # 将上面语句中的?再替换成%s res = ms.select(sql,value) # 结果肯定是[{},{},{}],是一个列表字典 if res: # 通过一个列表生成式将获取到的字典用**打散,然后传入类中完成实例化 return [cls(**r) for r in res] # 把数据库中的数据全部实例化成了对象 ##**把字典打散成了key=value的形式,比如(name = 'jason,password='123') def update(self): ms = Mysql() # 生成一个数据库操作的对象 #定义一个列表存储该表的所有字段名 fields = [] #定义一个变量来存储当前数据对象的主键 pr = None #定义一个列表用来装字段对应的值 args = [] for k,v in self.mappings.items(): # k是字段的名字,v是字段类产生的对象 #先判断谁是主键 if v.primary_key: #通过反射拿到主键对应的值 pr = getattr(self,v.name,v.default) # 如果没有就返回default中的值 else: #除了主键之外所有的字段取值 fields.append(v.name+'=?') # 把字段名拼成name=?,password=?这种形式 #获取除了主键字段之外所有字段的值 args.append(getattr(self,v.name,v.default)) #先用%s来代替字段名 sql = "update %s set %s where %s=%s"%( self.table_name,','.join(fields),self.primary_key,pr) #','.join(fields)就是把fields中的字段名拼成用,连接的字符串形式,也就是sql语句中写在set后面需要修改的字段内容 sql = sql.replace('?','%s') # 将上面最终拼接处的语句的?再替换成%s,拿到执行前最完整的sql语句 ms.execute(sql,args) # 执行sql语句,并传入%s代替的值 def save(self): ms = Mysql() # 生产一个数据库操作对象 #存字段名 fields = [] #存字段对应的值 values = [] #存?是用来代替字段值的,与字段名的数量相同 args = [] #拿到它的字段名和字段值 for k,v in self.mappings.items(): #去掉主键字段,一般就是是id,因为id是自动递增,所以不需要手动操作 if not v.primary_key: fields.append(v.name) #v字段对象,拿到字段名存到fields里 args.append('?') # 每存一个一个字段名存入一个用来占位字段的值的?; values.append(getattr(self,v.name,v.default)) # 拿到字段的名对应的值 sql = 'insert into %s(%s) values(%s)'%( self.table_name,','.join(fields),','.join(args)) #第一个%s是表名,第一个%s是字段名,第三个%s传入的是来占位对应字段名值的? #后两个都是用,隔开的形式如(name,age),(?,?) sql = sql.replace('?','%s') ms.execute(sql,values)
db_pool
from DBUtils.PooledDB import PooledDB import pymysql # pip3 install DBUtils POOL = PooledDB( creator=pymysql, # 使用链接数据库的模块 maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数 mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建 maxcached=5, # 链接池中最多闲置的链接,0和None不限制 maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] ping=0, # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always host='127.0.0.1', port=3306, user='root', password='123', database='youku_demo', charset='utf8', autocommit='True' )
mysql模块
class Mysql(object): def __init__(self): #建立连接通道,配置参数 self.conn = POOL.connection() #设置游标对象 self.cursor = self.conn.cursor(pymysql.cursors.DictCursor) #写一个关闭的方法,关闭光标和通道 def close_db(self): self.cursor.close() # 关闭光标 self.conn.close() # 关闭通道 #通过sql语句进行查询的方法 def select(self,sql,args=None): # 传入sql语句和参数(将参数的默认值设为None) self.cursor.execute(sql,args) # 执行传入的sql语句 res = self.cursor.fetchall() # 接收执行后的结果 return res # 将结果返回出来 #执行sql语句的方法 def execute(self,sql,args): try: self.cursor.execute(sql,args) # 执行sql语句 except BaseException as e: # 异常捕获,比如sql语句的传值有问题的时候捕获下来 print(e)