自我总结34

ORM升级版

'''
ORM: 对象关系映射 ---> 映射到数据库MySQL中的数据表

类名 ---> 表名
对象 ---> 一条记录
对象.属性 ---> 字段

模拟Django的ORM,为了,将数据库的 增、删、改、查,全部封装成
一个个的方式,比如: save, delete, update, select。


优点:
    使用者无需 关心具体的SQL命令 如何编写。
    直接通过调用方法 来执行相对应的SQL命令。

缺点:
    1.更高级的封装导致“执行效率变低”。
    2.会逐渐遗忘SQL原生命令。

'''


from mysql_client import MySQLClient


# 1.创建字段的类型, 对应数据表中的一个个字段的创建规范
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


# Integer
class IntegerField(Field):
    def __init__(self, name, column_type='int', primary_key=False, default =0):
        super().__init__(name, column_type, primary_key, default)


# String
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: 解决代码荣誉问题,比如有100张表,需要写100次__init__。
解决1: 继承一个父类,父类中定义一个__init__。

问题2: 无法预测每一张表中的字段是什么,无法通过父类的__init__解决问题。
解决2: 通过继承字典,内部的__init__, 可以接受“任意个数”的“关键字参数”。

问题3: 继承字典的类实例化的对象,无法通过“对象.属性”的方式存取值。
解决3: 通过__setattr__,__getattr__来实现,让字典对象与普通对象一模一样,并且具备字典原有的特性。


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


class OrmMetaClass(type):

    def __new__(cls, class_name, class_base, class_dict):

        # 过滤Models类
        if class_name == 'Models':
            return type.__new__(cls, class_name, class_base, class_dict)

        # 1.一张表必须要有表名
        # 假如table_name没有值,则将类名当做表名
        table_name = class_dict.get('table_name', class_name)  # get--> self.table_name

        # 2.主键名
        primary_key = None

        # 3.定义一个空字典, 专门用来存放字段对象
        mappings = {}

        # 遍历名称空间中所有的属性
        for key, value in class_dict.items():

            # 过滤字段对象以外的内容
            if isinstance(value,Field):

                # 判断字段对象primary_key是否为True
                if value.primary_key:

                    # 先判断初始的primary_key是否有值
                    if primary_key:  # 判断主键是否已存在
                        raise TypeError('只能有一个主键!')

                    # 若主键不存在,则给primary_值key赋
                    primary_key = value.name

        for key in mappings.keys():
            class_dict.pop(key)

        # 判断是否有主键
        if not primary_key:
            raise TypeError('必须有一个主键')

        # 给类的名称空间添加表名
        class_dict['table_name'] = table_name
        # 给类的名称空间添加主键名
        class_dict['primary_key'] = primary_key
        # 给类的名称空间添加一个mappings字典,字典中拥有所有字段属性
        class_dict['mappings'] = mappings
        return type.__new__(cls, class_name, class_base, class_dict)


class Models(dict, metaclass=OrmMetaClass):  # OrmMetaClass(Models, Models_name, base, class_dict)
    def __getattr__(self, item):
        # 将字典的值,返回
        return self.get(item)

    def __setattr__(self, key, value):
        self[key] = value

    # 查询方法
    # user.orm_select(id =1)

    @classmethod
    def orm_select(cls, **kwargs):

        mysql = MySQLClient()

        if not kwargs:
            # 查询所有sql:select *from User;
            sql = 'select * from %s' % cls.table_name

            res = mysql.my_select(sql)

        else:
            key = list(kwargs.keys())[0]
            value = kwargs.get(key)

            sql = 'select * from %s where %s=?' %(cls.table, key)
            sql = sql.replace('?', '%s')

            res = mysql.my_select(sql, value)

        return [cls(**d) for d in res]

    # 插入方法 User(传关键字参数) ---》 user_obj.orm_insert(user_obj)

    def orm_insert(self):
        mysql = MySQLClient()

        # 存储字段名
        keys = []

        # 存字段对应的值
        values= []

        # 存放?号的,有几个字段,就存几个?号
        args = []

        for k, v in self.mappings.items():
            # 过滤掉主键,因为主键是自增的
            if not v.primary_key:
                # 存表中除了主键以外的字段名
                keys.append(v.name)

                values.append(
                    getattr(self, v.name, v.default)
                )

                # 存放?号的,有几个字段,就存几个?号
                args.append('?')

        sql = 'insert into %s(%s) values(%s) '%(
            self.table_name,
            ','.join(keys),
            ','.join(args)
        )
        # sql: insert into table_name(v1, v2, v3) values(%s, %s, %s)
        sql = sql.replace('?', '%s')

        mysql.my_execute(sql, values)
        # mysql.cursor.execute(sql, values)

    # 更新方法 update User(传关键字参数)
    def orm_update(self):
        mysql = MySQLClient()
        # 字段名
        keys = []
        # 字段值
        values = []
        # 主键:id=pk
        primary_key = None

        for k,v in self.mappings.items():
            if v.primary_key:
                primary_key = v.name+'= %s' % getattr(self)

            else:
                keys.append(v.name+'=?')

                values.append(
                    getattr(self,v.name)
                )

        sql = 'update %s set %s where %s' % (
            self.table_name,
            ','.join(keys),
            primary_key
        )

        # sql: update table set k1=%s, k2=%s where id=pk; #
        sql = sql.replace('?', '%s')

        mysql .my_execute(sql, values)


# 用户表类
class User(Models):
    # table_name = 'user_info'
    # 强调: 最好与字段类型的name属性同名
    user_id = IntegerField(name='user_id',primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')


# 用户表类
class Movie(Models):
    user_if = IntegerField(name='user_id', primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='name')


if __name__ == '__main__':
    # ORM:类名 --> 表名     对象 ---> 一条记录     对象.属性 ---> 字段
    # user = User(user_name='tank', pwd='123')

    # 查  orm_select
    # 查询所有 sql: select * from User;
    # User.select()
    # Movie.orm_select()
    # 条件查询 sql: select * from User where id=1;
    # User.orm_select(id=1)
    # res = User.orm_select()[0]
    # print(res)
    # print(res.user_name)

    # 增  orm_insert
    # User表 ---> 添加字段对应的数据
    # user_obj = User(user_name='小贱贱', pwd='123')
    # user_obj.orm_insert()
    # user_obj = User.orm_select(user_name='小贱贱')[0]
    # print(user_obj.user_name)

    # 改
    # user_obj = User.orm_select(user_name='小贱贱')[0]
    # print(user_obj.user_name)
    # user_obj.user_name = '大贱贱'
    # user_obj.orm_update()
    user_obj = User.orm_select(user_name='djj')[0]
    print(user_obj)





posted @ 2019-11-05 21:40  jzm1201  阅读(70)  评论(0编辑  收藏  举报