zoukankan      html  css  js  c++  java
  • u库前戏

    u库

    ORM:对象关系映射
    类        》》》  数据库的一张表
    对象      》》》  表的一条记录
    对象点属性 》》》 记录某一个字段对应的值
    '''
    对象就是一个容器,里面装着属性和方法,而类就是盛放对象的一堆属性和方法,对象点来获取属性和方法。表就是装着一堆记录数据,通过对象点属性去获取某一个字段对应的值
    '''
    '''
    一个字段有字段名,字段类型,字段是否是主键,字段的默认值,通过类返回的对象去点这些属性
    '''
    the first step:
    先将表中的字段的各个属性字段名,字段类型,字段是否是主键,字段的默认值存放在类中,对象可以通过点来获取到某一个字段对应的值
    
    the second step:
    针对字段类型来写类,字段类型就有字符串类型(varchar,char),int
    先写一个可以定义varchar类型字段的类,再写定义一个整型字段的类
    
    the thrid step:
    定义三个类User,Notice,Movie,这三个类不能写__init__,用父类来写一个__init__,在实列化对象的时候,不管传多少个关键字实参我都可以满足,不同的对象传入的关键字实参不等,但都可以实例化被同一个父类实例化出来,能想到的是字典的实例化d=dict(),父类中就继承这个字典这个类就可以实现
    
    the fourth step:
    d=dict(name='json',password='123')
    name='json',password='123'这些都是对象属性对应的值,并不是对象的属性,所以d.name就是报错,(dict.get('name')这是字典的取值方式)
    '''
    有双杆的都表示自动触发
    '''
    __getattr__:在对象获取它没有的属性和方法的时候自动触发
    __setattr__:在对象点属性设置属性值的时候自动触发
    getattr():根据字符串获取对象对应属性和方法
    所以要在父类中加入def __getattr__和__setattr__来获取数据和修改数据
    
    the fifth step:
    一张表要有表名,一个主键,好多字段,说明这个类里面有表名,有字段,有主键,元类就是用来创建类,而现在的类就是对应的一张表,所以创建类就是创建表,在类创建之前就哟啊拦截这个类,将这些塞给这个类,才算是一张表
    user,notice,movie三个类是就是三个表,三个表都是继承models,所以models中继承元类。
    '''
    当类名为models时,就不需要拦截,原本该怎么创建就怎么创建,因为models并不是一张表,只是在创表的那个类继承models的方法,也就是用到字典类传参的那个功能而定义的类,之所以要models继承这个元类是因为是所有表类继承的父类,为了图方便就直接继承
    '''
    '''
    元类中的__new__就是造一个名称空间,为了拦截的是创建表格的创建,创建的空间需要类名和基类和类体。
    '''
    '''
    创建user这个类的时候,右键运行,会先跳到元类中,而user类中的代码也就是元类中class_attrs中的属性代码,所以元类中的class_attrs中已包含user中的代码还有自己为class_attrs这个字典自加的代码
    '''
    

    orm.py

    from mysql_singlenton import Mysql
    
    
    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
    
    
    # 先定义一个字符串类型,默认为varchar,默认主键为False,默认值为None
    class StringField(Field):
        def __init__(self, name, column_type='varchar(32)', primary_key=False, default=None):
            # 调用父类的__init__
            super().__init__(name, column_type, primary_key, default)
    
    
    # 定义一个整型字段的类
    class IntegerField(Field):
        def __init__(self, name, column_type='int', primary_key=False, default=None):
            super().__init__(name, column_type, primary_key, default)
    
    
    class MyMetaclass(type):
        def __new__(cls, class_name, class_bases, class_attrs):
            # 我们定义的元类是用来拦截模型表的创建过程,
            # 而models并不是一张模型表,所以不需要它的创建过程
            if class_name == 'Models':
                return type.__new__(cls, class_name, class_bases, class_attrs)
            # 获取类体代码中的属性,如果没有表名,就用类名来作为表名
            # 注意:get获取key,返回vaule,如果没有就返回None,如果写了第二个参数就返回第二个参数
            table_name = class_attrs.get('table_name', class_name)
            primary_key = None
            # 只要是表的字段的,我都放在字典中去,就不需要一个个去拿,直接拿到一个字典就有所有的字段了
            mappings = {}
            for k, v in class_attrs.items():
                # 拿出所有自己定义的表属性,过滤掉那个table_name
                # v是对象,Field是类,判断这个对象是否属于这个类
                if isinstance(v, Field):
                    mappings[k] = v
                    if v.primary_key:
                        # 以防创建两个主键
                        if primary_key:
                            raise TypeError('一张表只能有一个主键')
                        primary_key = k
            for k in mappings.keys():
                # 将单个的字段删除,for循环mappings拿到所有的字段
                class_attrs.pop(k)
            # 创建一个表有且要有一个主键,如果没有这个主键,那么就要报错
            if not primary_key:
                raise TypeError('一张表必须要有主键')
    
            # 以下是将所有在名称空间中的属性数据都保存起来,调用父类的__new__进行保存到名称空间中
            class_attrs['table_name'] = table_name
            class_attrs['primary_key'] = primary_key
            class_attrs['mappings'] = mappings
            return type.__new__(cls, class_name, class_bases, class_attrs)
    
    
    class Models(dict, metaclass= MyMetaclass):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
    
        # self是字典的对象,
        def __getattr__(self, item):
            self.get(item, '没有该键')  # 在没有这个item这个值的时候才会触发后面的‘没有该键’
    
        def __setattr__(self, key, value):
            try:
                self[key] = value
            except BaseException as e:
                print(e)
    
        @classmethod
        def select(cls, **kwargs):
            # 调用Mysql的查询方法
            ms = Mysql.singleton()
            # select * from %s
            # 当没有参数传入,代表查询所有的数据
            if not kwargs:
                sql = 'select * from %s' % cls.table_name
                res = ms.select(sql)
            else:
                k = list(kwargs.keys())[0]
                v = kwargs.get(k)
                sql = "select * from %s where %s=?" % (cls.table_name, k)
                sql = sql.replace('?', '%s')
                res = ms.select(sql, v)
            if res:
                print(res)
                return [cls(**r) for r in res]
            # select * from %s where %s=%s
    
    
    if __name__ == '__main__':
        class User(Models):
            table_name = 'userinfo'
            id = IntegerField(name='id', primary_key=True)
            name = StringField(name='name')
    
    
    
        rs = User.select(password='123')
        print(rs)
    
    
        class Notice(Models):
            pass
    
    
        class Movie(Models):
            pass
    

    mysql_singlenton.py

    import pymysql
    
    class Mysql(object):
        _instance = None
        def __init__(self):
            self.conn = pymysql.connect(
                host='127.0.0.1',
                port=3306,
                user='root',
                password='123',
                database='day41',
                charset='utf8',
                autocommit=True
            )
            self.cursor = self.conn.cursor(pymysql.cursors.DictCursor)
    
        def close_db(self):
            self.cursor.close()
            self.conn.close()
    
        def select(self,sql,args=None):
    
            self.cursor.execute(sql,args)
            # 注意一点:fetchall拿到的数据结构是一个列表套字典[{},{},{}]
            res = self.cursor.fetchall()
            return res
    
        def execute(self, sql,args):
            #insert into user(name,password) values('jason','123')
            #update user set name='jason',password='456' where id=1
            try:
                self.cursor.execute(sql,args)
            except BaseException as e:
                print(e)
    
        @classmethod
        def singleton(cls):
            if not cls._instance:
                cls._instance = cls()
            return cls._instance
    
  • 相关阅读:
    error: device not found
    RK3288 查看时钟树
    GPS数据包格式解析
    Android 操作文件系统失败: Read-only file system
    Ubuntu 14.04 配置安卓5.1编译环境
    升级 php composer 版本
    清理 laravel blade 模板缓存
    Laravel collection 报错 join(): Invalid arguments passed
    Laravel firstOrNew 与 firstOrCreate 的区别
    执行 crontab 的计划任务
  • 原文地址:https://www.cnblogs.com/huangxuanya/p/10897216.html
Copyright © 2011-2022 走看看