zoukankan      html  css  js  c++  java
  • orm初识

    
    
    ORM:对象关系映射
    类 》》》 数据库的一张表
    对象 》》》 表的一条记录
    对象点属性 》》》 记录某一个字段对应的值

    """
    表----映射出数据库的一张表 1、通过类实例化对象,得到表的某一个字段,基于基类Field定义两个子类StringField,IntegerField,这样定义会更明确一点 2、某一个东西某一个类怎么传参数都能实例化出来---字典dict 3、继承字典的__init__ 4.对象点一个不存在的属性的时候会自动触发内部了__getattr__ 5、对象点属性设置属性值得时候触发,添加或更改字典值 self[k]=v 对象---映射出表的一条记录 1、通过元类实现类的创建 __new__创建空对象的时候,获取到类里面的名称空间class_attrs 2、拿到名称空间就可以修改,可以拿到用户写的字段也可以拿到默认的 3、创建类的时候定义一个table_name,如果没有的话让表名class_name,当table_name 4、拿到所有标识表字段的key,values,如果是字段属性存放在mappings字典 5、判断是不是主键,不能有两个主键,否则报错提醒 6、循环mappings拿到的所有自定义字段名,将单个单个的字段删除 """
    orm.py代码
    from
    mysql_singleton 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字段类型 class StringField(Field): def __init__(self,name,column_type='varchar(32)',primary_key=False,default=None): super().__init__(name,column_type,primary_key,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)
    #定义一个元类
    class MyMetaClass(type):
        def __new__(cls,class_name,class_bases,class_attrs):
            #定义的元类是用来拦截模型表的创建过程,而models并不是一张模型表,所以不需要它的创建过程
            if class_name =='Models':  #从子类Models拿到字段名
                return type.__new__(cls,class_name,class_bases,class_attrs)
            #创建类的时候定义一个table_name,如果没有的话让表名class_name,当table_name
            table_name =class_attrs.get('table_name',class_name)
            primary_key=None
            #映射存放在字典里
            mappings={}
            #下面的for循环需要做两件事
            # 1、将单个单个的字段整合成一个
            # 2、确定当前表哪个字段是主键
            #拿到所有标识表字段的key,values
            for k,v in class_attrs.items():
                #拿出所有自己定义的表的字段属性
                #如果是字段属性存放在mappings字典
                if isinstance(v,Field):
                    mappings[k]=v
                    #接着判断是不是主键
                    #如果是True就执行61行赋值
                    if v.primary_key:
                        #健壮性校验一张表不能有多个主键
                        if primary_key:
                            raise TypeError('一张表不能有多个主键')
                        primary_key =v.name  #字段设为主键
            #循环mappings拿到的所有自定义字段名
            for k in mappings.keys():
                # 最后需要把mappings加到了class_attrs里面,所以要把游离在外的删掉,用mappings存所有的
                #将单个单个的字段删除
                class_attrs.pop(k)
            #校验用户自定义的模型表是否制定了主键字段
            #如果没有一个主键报错
            if not primary_key:
                raise TypeError('一张表必须有一个主键')
            #将标示表的特征信息,表名,表的主键字段,表的其他字段都塞到类的名称空间中
            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)
    #所有的模型表都继承Models
    class Models(dict, metaclass=MyMetaClass):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
    
        def __getattr__(self, item):
            return self.get(item,'没有该键!')
    
        def __setattr__(self, key, value):
            self[key] = value
    
        #查询操作最小识别单位是表
        #需要查询每一张表,绑定给类,用类查询表
        @classmethod
        def select(cls,**kwargs):
            #实例化产生一个查询对象
            #做成单例模式是因为防止过多用户访问
            ms=Mysql.singleton()
            #查询表分两种情况
            # 1、select * from %s
            # 2、select * from %s where %s=%s
            #第一种情况不需要传参数
            if not kwargs:
                sql="select * from %s"%cls.table_name
                #对象点方法把sql语句传给过去返回个res
                res=ms.select(sql)
            else:
                #第二种有参数的情况 比如name='jason' id='1'
                #只能有一个过滤条件
                k=list(kwargs.keys())[0]
                v=kwargs.get(k)
                #如果下面"?"变成"%s" 就要手动传值
                #让mysql的execute函数去拼字符串
                sql="select * from %s where %s=?"%(cls.table_name,k)
                sql=sql.replace('?','%s')
                res=ms.select(sql,v)
            #如果查询到有结果
            if res:
                #res=[{},{},{}]
                return [cls(**r) for r in res]
            #**打散成:name='jason',password='123
            #精髓:把mysql里的数据真正的转换成一个对象!!!
    if __name__ == '__main__':
        class Teacher(Models):
            table_name='teacher'
            tid=IntegerField(name='tid',primary_key=True)
            tname=StringField(name='tname')
    
    
        res1 = Teacher.select(tname='李平老师')
        print(res1)
        obj1 = res1[0]
        print(type(obj1))

    mysql_singlethon代码

    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='new_school',
                charset='utf8',
                autocommit=True
            )
            #游标
            self.cursor=self.conn.cursor(pymysql.cursors.DictCursor)
        def class_db(self):
            self.cursor.close()
            self.conn.close()
    
        #这里的args是查询sql语句的过滤条件传过来的参数
        def select(self,sql,args=None):
            self.cursor.execute(sql,args)
            res=self.cursor.fetchall() #fetchall拿到的是一个列表套字典的形式
            return res
    
        def execute(self,sql,args):
            try:
                self.cursor.execute(sql,args)
            except BaseException as e:
                print(e)
    
        @classmethod
        def singleton(cls):
            #如果没有值,代表一次都没实例化
            if not cls._instance:
                #实例化对象
                cls._instance=cls()
            # 返回对象,第二次来的时候直接返回不用走36行代码,返回的值就是上一次产生的对象
            return cls._instance
  • 相关阅读:
    JQ选择器
    设计模式
    招银网络面试
    斗鱼面经
    招银科技面经
    用户访问网站基本流程
    shell的条件判断
    crontab -e 和/etc/crontab的区别
    秘钥对登录配置
    CentOS6 x86_64最小化安装优化脚本
  • 原文地址:https://www.cnblogs.com/zhengyuli/p/10895908.html
Copyright © 2011-2022 走看看