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

猜你喜欢

转载自www.cnblogs.com/huangxuanya/p/10897216.html