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

 

转载于:https://www.cnblogs.com/zhengyuli/p/10895908.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值