zoukankan      html  css  js  c++  java
  • python 其实不用框架你也可以实现ORM

    """
    ORM思路归纳:
    
        1、将每张表映射成不同的表类,一个表类映射一张表。表类的类属性
            需要有表名、字段名
            将每个字段类型映射为字段类型类,一个字段类型类映射一个类
            字段类实例化需要传入有字段名、字段类型、是否是主键、默认值
            等参数,其中除字段名外其他参数可设置默认值
        2、每个表类都有相同的基础属性,如表名,主键字段,增删改查方法,
            那么由此就可以抽离出Models基类,相同属性和方法同一抽到基类,
            不涉及需要每个表区别属性的方法我们把它抽为基类类方法。
        3、考虑到一条数据库数据需要产生一个对象,用pymysql查询得到得可以
            是字典类型,那么我们可以将基类Models继承dict,用__setattr__
            将字段转换为伪对象属性操作,用__getattr__对属性取值
            由基类查询一条或者多条数据的类方法,将得到的记录本身传给表类
            自身实例化得到对象,用__setattr__将字段作为对象属性,这样一
            个对象就可以映射一条数据
        4、为了更好的实现对数据库表的映射,我们需要创建元类来对定义的表类
            的控制,如一个表只且只有一个主键,规范每个表类的属性名称,比如
            表名、主键名,其他字段集合
        5、另外要实现对数据库操作提交,这部分功能不适合做在基类表类中,做在
            表类中会让表类臃肿且逻辑不清,我们将其专门定义一个数据库连接类,
            表这一部分就负责实现功能,具体对数据库通信操作由数据库连接类去完成
    
    """
    
    # 实现代码
    
    class Field(object):
        """
        Field:映射数据库字段 基类
        name:字段名
        culomn_type:字段类型
        primary_key:是否是主键
        default:默认值
        """
        def __init__(self,name,culomn_type,primary_key,default):
            self.name = name
            self.culomn_type = culomn_type
            self.primary_key = primary_key
            self.default = default
    
    class IntField(Field):
        """
        继承Field基类,实现对int类型字段的映射
        """
        def __init__(self,name,culomn_type = "int",primary_key = False,default = 0):
            super().__init__(name,culomn_type,primary_key,default)
    
    
    class PrimaryField(Field):
        """
            继承Field基类,实现对主键字段的映射
        """
        def __init__(self,name,culomn_type,primary_key = True, default = None):
            super().__init__(name,culomn_type,primary_key,default)
    
    
    class StringField(Field):
        """
            继承Field基类,实现对char类型字段的映射
        """
        def __init__(self,name,culomn_type = "varchar(64)", primary_key = False,default = ""):
            super().__init__(name,culomn_type,primary_key,default)
    
    # 你还可以继续定义其他类型字段类,如日期等
    
    



    class MyMeta(type): """ 自定义元类,实现对每张表映射的表类的属性控制 如:1、限制一个表有且只能有一个主键,否则创建派生类失败 2、将表的字段属性全部放到一个字典里,然后把这个字典整体放入类的名称空间 """ def __new__(cls, class_name, class_bases, class_space): # 控制类产生 if class_name == "Models": # 对 Models类不生效 # 所有表类由Models类派生 return type.__new__(cls,class_name,class_bases, class_space) table_name = class_space.get("table_name") primary_key = None mappings = {} for k,v in class_space.items():# 筛选出主键 if isinstance(v,Field): mappings[k] = v if v.primary_key: if primary_key: raise TypeError("一个表只能有一个主键") primary_key = v for key in mappings.keys(): # 将原名称空间中的所有字段属性删除 class_space.pop(key) class_space["table_name"] = table_name class_space["primary_key"] = primary_key # 将筛选出来的属性重新装回类名称空间 class_space["mappings"] = mappings # 将字段属性装入mapping再装回原名称空间 return type.__new__(cls,class_name,class_bases,class_space) # 调回type__new__ class Models(dict,metaclass = MyMeta): 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): # 查询表单条或多条记录,并实例化记录为对象返回 mysql = Mysql.create_instance() if not kwargs: sql = "select * from %s"%cls.table_name res = mysql.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 = mysql.select(sql,(v,)) if res: return [cls(**r) for r in res] import pymysql class Mysql(object) : _instance = None def __init__(self): # 建立数据库连接 self.conn = pymysql.connect( host = "127.0.0.1", port = 3306, user = "root", password = "123456", database = "class", charset = "utf8", autocommit = True ) self.cursor = self.conn.cursor(pymysql.cursors.DictCursor) # 设置查询返回数据格式为列表套字典 @classmethod def create_instance(cls): # 创建单例 if not cls._instance: cls._instance = cls() return cls._instance def select(self,sql,arg = None): # 提交数据库操作 if not arg: try: self.cursor.execute(sql) except BaseException as e: print(e) return else: try: self.cursor.execute(sql,arg) except BaseException as e: print(e) return res = self.cursor.fetchall() # 拿到所有返回结果 return res if __name__ == '__main__': class Course(Models): # course表类 table_name = "course" cid = PrimaryField(name = "cid",culomn_type="int") # 表id字段 创建主键字段对象 cname = StringField(name = "cname") # 表cname字段,创建字符串类型对象 res = Course.select(cid = 3) # 查找cid = 3的记录并实例化对象返回 print(res[0].cname) print(res[0].mappings)
  • 相关阅读:
    【我读cachecloud】cachecloud-open-web模块controller
    【我读cachecloud】cachecloud项目概述
    [转]Kerberos协议
    【shell】我的wait为什么不能用
    【 一次性密码】TOTP
    【shell】再看一眼find--find使用中遇到的问题分析
    我知道点redis-单机数据库(RDB持久化)
    我知道点redis-数据结构与对象(对象)-对象实现
    我知道点redis-数据结构与对象(对象)-对象存储
    我知道点redis-数据结构与对象(链表)
  • 原文地址:https://www.cnblogs.com/dongxixi/p/10897254.html
Copyright © 2011-2022 走看看