模拟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__方法,奇怪,不是在构造类的时候会去找父类的元类吗?

找时间把这个坑彻底填了

 

posted @ 2020-04-04 11:21  olivertian  阅读(211)  评论(0编辑  收藏  举报