zoukankan      html  css  js  c++  java
  • ORM

    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)
  • 相关阅读:
    WIndows 常见问题解决方案合集
    【日常摘要】- RabbitMq实现延时队列
    【工具】- HttpClient篇
    【java面试】- 集合篇
    【Java面试】- 并发容器篇
    【mysql】- 锁篇(上)
    【mysql】- 锁篇(下)
    【mysql】- 事务隔离级别和MVCC篇
    【mysql】- 索引使用篇
    【mysql】- 索引简介篇
  • 原文地址:https://www.cnblogs.com/wangnanfei/p/ORM.html
Copyright © 2011-2022 走看看