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)
  • 相关阅读:
    [LeetCode] Power of Three 判断3的次方数
    [LeetCode] 322. Coin Change 硬币找零
    [LeetCode] 321. Create Maximum Number 创建最大数
    ITK 3.20.1 VS2010 Configuration 配置
    VTK 5.10.1 VS2010 Configuration 配置
    FLTK 1.3.3 MinGW 4.9.1 Configuration 配置
    FLTK 1.1.10 VS2010 Configuration 配置
    Inheritance, Association, Aggregation, and Composition 类的继承,关联,聚合和组合的区别
    [LeetCode] Bulb Switcher 灯泡开关
    [LeetCode] Maximum Product of Word Lengths 单词长度的最大积
  • 原文地址:https://www.cnblogs.com/wangnanfei/p/ORM.html
Copyright © 2011-2022 走看看