使用元类实现Django的ORM

一、ORM基本介绍

tex 复制代码
ORM 是 python编程语言后端web框架 Django的核心思想,"Object Relational Mapping",即对象-关系映射,简称ORM。

二、实现目标

tex 复制代码
创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句

如图:

三、代码实现

python 复制代码
class ModelMetaClass(type):

    def __new__(cls, name, bases, attrs):
        mappings = dict()
        for k, v in attrs.items():
            # 只处理类中属性值为元组的键值对
            if isinstance(v, tuple):
                mappings[k] = v

        # 处理完成后删除属性
        for k in mappings:
            attrs.pop(k)

        attrs["__mappings__"] = mappings
        attrs["__table__"] = name
        # 这里不能用type(name, bases, attrs) 直接返回创建好的类, 不会触发type的__init__方法
        return type.__new__(cls, name, bases, attrs)


class Model(metaclass=ModelMetaClass):
    # uid = ("uid", "int unsigned")
    # name = ("username", "varchar(30)")
    # email = ("email", "varchar(30)")
    # password = ("password", "varchar(30)")

    def __init__(self, **kwargs):
        # 将关键字参数添加到实例属性
        for k, v in kwargs.items():
            setattr(self, k, v)

    def save(self):
        table_name = self.__table__
        field = list()
        args = list()
        for k, v in self.__mappings__.items():
            field.append(v[0])
            arg = getattr(self, k, None)
            # ["12345","""'Michael'""","""'test@orm.org'""","""'my-pwd'"""]
            if isinstance(arg, str):
                args.append("""'{}'""".format(arg))
            else:
                args.append(str(arg))

        sql = "insert into {}({}) values ({})".format(table_name, ",".join(field), ",".join(args))
        print(f"SQL语句: {sql}")


class User(Model):
    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()

代码运行结果: