• 简单ORM的实现


    简单的orm实现

    我们在使用各种框架的时候,关于数据库这方面的使用,框架给我们提供了很好的封装,这个就是orm

    关系映射

    orm的底层无非就是做了关系映射

    数据库的表(table) --> 类(class)
    记录(record,行数据)--> 对象(object)
    字段(field)--> 对象的属性(attribute)
    

    ORM设计

    字段

    首先是字段,每个字段都有很多的字段属性,然后考虑到,每个表的字段可能都不同,为了给他提供更好的拓展性,所以这里我们选择用类来封装

    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
    
    class StringField(Field):
        def __init__(self,name,
                     column_type='varchar=(255)',
                     primary_key=False,
                     default=None):
            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 Teacher(Models):
        print("teacher")
        table_name='teacher'
        tid = IntegerField(name='tid',primary_key=True)
        tname = StringField(name='tname')
    

    为了能更好的展示,dict数据类型更适合我们,所以最后让他继承dict,但是字典取值只能通过key取值,这样不方便,所以我们也要改写他的取值方式为.取值

    class Models(dict,metaclass=ModelMetaClass):
        print("Models")
        def __init__(self,**kwargs):
            print(f'Models_init')
            super().__init__(self,**kwargs)
    
        def __getattr__(self, item):
            return self.get(item,"没有该值")
    
        def __setattr__(self, key, value):
            self[key]=value
    

    为了确保我们自己定义表的的时候不会有错误,我们需要加一步,字段的检测步骤,并对字段更好整理

    class ModelMetaClass(type):
        print("ModelMetaClass")
        def __new__(cls,class_name,class_base,class_attrs):
            print("ModelMetaClass_new")
            #实例化对象的时候也会执行,我们要把这一次拦截掉
            if class_name == 'Models':
                #为了能让实例化顺利完成,返回一个空对象就行
                return type.__new__(cls,class_name,class_base,class_attrs)
            #获取表名
            table_name = class_attrs.get('table_name',class_name)
    
            #定义一个存主键的的变量
            primary_key = None
    
            #定义一个字典存储字段信息
            mapping = {}
    
            #name='tid',primary_key=True
            #for来找到主键字段
            for k,v in class_attrs.items():
                #判断信息是否是字段
                if isinstance(v,Field):
                    mapping[k] = v
                    #寻找主键
                    if v.primary_key:
                        if primary_key:
                            raise TypeError("主键只有一个")
                        primary_key=v.name
    
            #将重复的键值对删除,因为已经放入了mapping
            for k in mapping.keys():
                class_attrs.pop(k)
            if not primary_key:
                raise TypeError("表必须要有一个主键")
            class_attrs['table_name']=table_name
            class_attrs['primary_key']=primary_key
            class_attrs['mapping']=mapping
            return type.__new__(cls,class_name,class_base,class_attrs)
    

    数据库操作

    数据库操作最好就是放在类里面,然后使用类方法

        #查找
        @classmethod
        def select(cls,**kwargs):
            ms=MySQL()
    
            #如果没有参数默认是查询全部的
            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=sql.replace('?','%s')
    
                res=ms.select(sql,v)
            if res:
                return [cls(**i) for i in res]
    
        #新增
        def save(self):
            ms=MySQL()
    
            #存字段名
            fields=[]
            #存值
            values=[]
            args=[]
    
            for k,v in self.mapping.items():
                #主键自增,不用给他赋值
                if not v.primary_key:
                    fields.append(v.name)
                    args.append("?")
                    values.append(getattr(self,v.name))
    
                sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args)))
    
                sql = sql.replace('?','%s')
    
            ms.execute(sql,values)
    
        def update(self):
            ms = MySQL()
            fields = []
            valuse = []
            pr = None
            for k,v in self.mapping.items():
                #获取主键值
                if v.primary_key:
                    pr = getattr(self,v.name,v.default)
                else:
                    fields.append(v.name+'=?')
                    valuse.append(getattr(self,v.name,v.default))
                print(fields,valuse)
            sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr)
    
            sql = sql.replace('?',"%s")
    
            ms.execute(sql,valuse)
    

    Mysql连接

    import pymysql
    
    
    class MySQL:
    
        #单例模式
        __instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = object.__new__(cls)
            return cls.__instance
    
        def __init__(self):
            self.mysql = pymysql.connect(
                host='127.0.0.1',
                port=3306,
                user='root',
                database='orm_demo',
                password='root',
                charset='utf8',
                autocommit=True
            )
    
            #获取游标
            self.cursor = self.mysql.cursor(
                pymysql.cursors.DictCursor
            )
    
        #查看
        def select(self,sql,args=None):
            #提交sql语句
            self.cursor.execute(sql,args)
    
            #获取查询的结果
            res = self.cursor.fetchall()
            return res
    
        #提交
        def execute(self,sql,args):
            #提交语句可能会发生异常
            try:
                self.cursor.execute(sql,args)
            except Exception as e:
                print(e)
    
        def close(self):
            self.cursor.close()
            self.mysql.close()
    

    整体代码部分

    MySQL.py

    import pymysql
    
    
    class MySQL:
    
        #单例模式
        __instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = object.__new__(cls)
            return cls.__instance
    
        def __init__(self):
            self.mysql = pymysql.connect(
                host='127.0.0.1',
                port=3306,
                user='root',
                database='orm_demo',
                password='root',
                charset='utf8',
                autocommit=True
            )
    
            #获取游标
            self.cursor = self.mysql.cursor(
                pymysql.cursors.DictCursor
            )
    
        #查看
        def select(self,sql,args=None):
            #提交sql语句
            self.cursor.execute(sql,args)
    
            #获取查询的结果
            res = self.cursor.fetchall()
            return res
    
        #提交
        def execute(self,sql,args):
            #提交语句可能会发生异常
            try:
                self.cursor.execute(sql,args)
            except Exception as e:
                print(e)
    
        def close(self):
            self.cursor.close()
            self.mysql.close()
    
    

    orm.py

    from MySQL 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
    
    class StringField(Field):
        def __init__(self,name,
                     column_type='varchar=(255)',
                     primary_key=False,
                     default=None):
            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 ModelMetaClass(type):
        print("ModelMetaClass")
        def __new__(cls,class_name,class_base,class_attrs):
            print("ModelMetaClass_new")
            #实例化对象的时候也会执行,我们要把这一次拦截掉
            if class_name == 'Models':
                #为了能让实例化顺利完成,返回一个空对象就行
                return type.__new__(cls,class_name,class_base,class_attrs)
            #获取表名
            table_name = class_attrs.get('table_name',class_name)
    
            #定义一个存主键的的变量
            primary_key = None
    
            #定义一个字典存储字段信息
            mapping = {}
    
            #name='tid',primary_key=True
            #for来找到主键字段
            for k,v in class_attrs.items():
                #判断信息是否是字段
                if isinstance(v,Field):
                    mapping[k] = v
                    #寻找主键
                    if v.primary_key:
                        if primary_key:
                            raise TypeError("主键只有一个")
                        primary_key=v.name
    
            #将重复的键值对删除,因为已经放入了mapping
            for k in mapping.keys():
                class_attrs.pop(k)
            if not primary_key:
                raise TypeError("表必须要有一个主键")
            class_attrs['table_name']=table_name
            class_attrs['primary_key']=primary_key
            class_attrs['mapping']=mapping
            return type.__new__(cls,class_name,class_base,class_attrs)
    
    class Models(dict,metaclass=ModelMetaClass):
        print("Models")
        def __init__(self,**kwargs):
            print(f'Models_init')
            super().__init__(self,**kwargs)
    
        def __getattr__(self, item):
            return self.get(item,"没有该值")
    
        def __setattr__(self, key, value):
            self[key]=value
    
        #查找
        @classmethod
        def select(cls,**kwargs):
            ms=MySQL()
    
            #如果没有参数默认是查询全部的
            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=sql.replace('?','%s')
    
                res=ms.select(sql,v)
            if res:
                return [cls(**i) for i in res]
    
        #新增
        def save(self):
            ms=MySQL()
    
            #存字段名
            fields=[]
            #存值
            values=[]
            args=[]
    
            for k,v in self.mapping.items():
                #主键自增,不用给他赋值
                if not v.primary_key:
                    fields.append(v.name)
                    args.append("?")
                    values.append(getattr(self,v.name))
    
                sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args)))
    
                sql = sql.replace('?','%s')
    
            ms.execute(sql,values)
    
        def update(self):
            ms = MySQL()
            fields = []
            valuse = []
            pr = None
            for k,v in self.mapping.items():
                #获取主键值
                if v.primary_key:
                    pr = getattr(self,v.name,v.default)
                else:
                    fields.append(v.name+'=?')
                    valuse.append(getattr(self,v.name,v.default))
                print(fields,valuse)
            sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr)
    
            sql = sql.replace('?',"%s")
    
            ms.execute(sql,valuse)
    
    
    class Teacher(Models):
        print("teacher")
        table_name='teacher'
        tid = IntegerField(name='tid',primary_key=True)
        tname = StringField(name='tname')
    
    if __name__ == '__main__':
        # tea=Teacher(tname="haha")
        tea2=Teacher(tname="haha",tid=5)
        # print(Teacher.select(tid=1))
        # Teacher.save(tea)
        print(Teacher.update(tea2))
    
    
  • 相关阅读:
    深入了解SQLServer系统数据库工作原理(转)
    什么是动态语言(转)
    ASP.NET 2.0客户端回调的实现分析
    什么是“分布式应用系统”
    SQLServer数据库安全管理机制详解
    什么是 CLR(转)
    docker容器下的asp.net core项目发布运维
    VLAN技术
    用getDrawingCache方法获取ImageView中的图像需要注意的问题
    交换机的工作原理
  • 原文地址:https://www.cnblogs.com/zx125/p/11613054.html
Copyright © 2020-2023  润新知