欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于元类实现ORM

程序员文章站 2022-05-31 23:29:22
...
"""
基于元类,实现ORM--模拟django
"""

# Field定义字段基类,包括字段名字和字段类型
class Field(object):
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type
    # 定义可读性更好的__str__()
    def __str__(self):
        return f'<{self.__class__.__name__}: {self.name}>'

# 定义charField类
class CharField(Field):
    def __init__(self, name, max_length):
        super().__init__(name, f'varchar({max_length})')

# 定义Integer类
class IntegerField(Field):
    def __init__(self, name):
        super().__init__(name, 'int')

# 定义模型基类
class ModelMeta(type):
    # attrs 是字典对象
    def __new__(cls, name, bases, attrs):# 查看这个attr的键值对
        if name == 'Model':
            return type.__new__(cls, name, bases, attrs)

        print('Model name : ', name)# 会自动传送类名过来
        mappings = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                print('Field Mapping',(k, v))
                mappings[k] = v
        # 便利mappings 将字典attrs中的键删掉
        for k in mappings:
            attrs.pop(k)

        attrs['__mappings__'] = mappings
        attrs['__table__'] = name

        return type.__new__(cls, name, bases, attrs)


class Model(dict, metaclass=ModelMeta):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def __getattr__(self, key):
        try:
            return self[key]
        except:
            raise AttributeError(f'Model not {key} key')

    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        params = []
        args = []
        # __mappings__是一个字典
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))

        sql = 'insert into %s(%s) VALUES (%s)' 
        % (self.__table__, ','.join(fields), ','.join(params))
        print(sql, args)


class Person(Model):
    id = IntegerField(name='pid')
    name = CharField('pname', max_length=20)
    age = IntegerField('age')


if __name__ == '__main__':
    p = Person(id=1, name='disen', age=20)
    p.save()

Q&A

  1. args.append(getattr(self, k, None))为啥能够获得用户输入的值,而不是类变量
  2. for k, v in self.mappings.items():此处字典__mappings__中的键值对则是变成如下图中的Field Mapping括号中所示
    基于元类实现ORM
  3. 对1,2 两点的猜测,涉及到类变量和实例变量getattr()得到的是当前实例变量的属性,而底层(父类)得到的则是类变量