1105 笔记

ROM框架

ORM对象映射关系
类名       --       表名
对象       --       记录
对象.属性  ---      字段

1.定义表字段的类型

2.创建元类,限制表类的创建

'''
元类需要处理的问题:
    1.一张表必须要有一个表名。
    2.给数据表类,强制必须要有一个主键,主键必须是唯一的。
    3.将数据表中,所有的字段对象,都存放在一个独立的字典中
        存不是目的,目的是为了取值方便。
'''
  1. 过滤Models类,models类中,什么都不做,将类原路返回。

  2. 一张表必须有表名,如果没有则将类名做表名

    1. 表名
      主键名
      定义一个空字典,用来存放字段对象
  3. 遍历名称空间的属性判断主键的存在与否

  4. 节省资源: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()

猜你喜欢

转载自www.cnblogs.com/fwzzz/p/11802226.html