模拟django orm实现遇到的坑
""" 核心理念就是:类属性对应为便于用户理解的字段名(如name),而数据库中保存的是另一个字段名(如用户字段名name对应数据库实际 保存的字段名为username),当调用save时,要将便于用户理解的字段名转化为实际数据库保存的用户名 """ class ModelMetaclass(type): def __new__(cls, cls_name, bases, attrs): print("*" * 20, cls, " ", cls_name) mappings = dict() for k, v in attrs.items(): if isinstance(v, tuple): mappings[k] = v for k in mappings.keys(): attrs.pop(k) attrs["__mappings__"] = mappings attrs["__table__"] = cls_name # 以User为例,User类中的属性,经过元类的改造,就变成下面的__mappings__字典 # __mapping__ = { # "uid": ("uid", "int unsigned"), # "name": ("username", "varchar(30)"), # "email": ("email", "varchar(30)"), # "password": ("password", "varchar(30)") # } # __table__ = "User" , 类名就是表名 return type(cls_name, bases, attrs) class Model(metaclass=ModelMetaclass): def __init__(self, **kwargs): for name, value in kwargs.items(): setattr(self, name, value) def save(self): fields = [] # 实际保存在数据库中的字段名 args = [] # 用户传入的值 for k, v in self.__mappings__.items(): fields.append(v[0]) args.append(getattr(self, k, None)) args_temp = list() for item in args: if isinstance(item, int): args_temp.append(str(item)) if isinstance(item, str): args_temp.append("""'%s'""" % item) print(self.__table__, self.__mappings__) sql = "insert into %s (%s) values (%s)" % (self.__table__, ",".join(fields), ",".join(args_temp)) print("SQL: %s" % sql) class User(Model): def __init__(self, **kwargs): super().__init__(**kwargs) uid = ("uid", "int unsigned") name = ("username", "varchar(30)") email = ("email", "varchar(30)") password = ("password", "varchar(30)") u = User(uid=12345, name="Michael", email="test@orm.org", password="my-pwd") u.save()
目的是类继承Model时就能使用ModelMetaclass去改造之,比如定义了User类,继承了Model,希望在构造User类时,使用ModelMetaclass去做一些自定义的改造,然而发现构造User时根本就没有调用ModelMetaclass.__new__方法,只有构造Model类时调用了ModelMetaclass.__new__方法,奇怪,不是在构造类的时候会去找父类的元类吗?
找时间把这个坑彻底填了