廖雪峰笔记——元类metaclass与ORM模型

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319106919344c4ef8b1e04c48778bb45796e0335839000


http://blog.jobbole.com/21351/


https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python


个人理解:

DAG: dict <- Model <- User (ModelMetaclass(type)作用于User类的创建)

执行过程:用metaclass创建User类,再创建实例u


1、类的创建:dict <- Model <- User (ModelMetaclass(type)作用于User类的创建)

Model类按默认创建,ModelMetaclass(type)作用于User类的创建:

class ModelMetaclass(type):

    def __new__(cls, name, bases, attrs):
        if name=='Model':
            return type.__new__(cls, name, bases, attrs)
        print('Found model: %s' % name)
        mappings = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                print('Found mapping: %s ==> %s' % (k, v))
                mappings[k] = v
        for k in mappings.keys():
            attrs.pop(k)
        attrs['__mappings__'] = mappings # 保存属性和列的映射关系
        attrs['__table__'] = name # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)

在创建User类时,中name == User, bases == Model, attrs 是即将创建的类 User的类属性

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

元类会自动将你通常传给‘type’的参数作为自己的参数传入
):

class User(Model):
    # 定义类的属性到列的映射:
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')


相当于在attrs处传入了  字典{  'id': IntegerField('id'),  'name': 'StringField('username'),  'email': StringField('email),  'password': StringField('password')    };

那么for k, v in attrs.items()中,k 为'id'等(赋值号左边),'v'为IntegerField('id')实例等(赋值号右边);

在当前类(比如User)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__的dict中,同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性)详见:实力属性和类属性 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319117128404c7dd0cf0e3c4d88acc8fe4d2c163625000

Output:

Found model: User
Found mapping: email ==> <StringField:email>
Found mapping: password ==> <StringField:password>
Found mapping: id ==> <IntegerField:id>
Found mapping: name ==> <StringField:username>


2、u = User(..........)

u有类属性attrs['__mappings__'] = mappings, 同时u也是一个dict实例,{'id':12345, 'name':'Michael', ........................}


u.save()

 def save(self):
        fields = []
        params = []
        args = []
        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: %s' % sql)
        print('ARGS: %s' % str(args))
Output:

SQL: insert into User (password,email,username,id) values (?,?,?,?)
ARGS: ['my-pwd', 'test@orm.org', 'Michael', 12345]
k 与 v 在__mappings__.items()中分别为key 和 value(类型为Field)

k 在 self 即{'id':12345, 'name':'Michael', ........................}(类型为User,继承自dict)中为key, 当k为'id'时,返回12345


id = IntegerField('id')    右边是列(表头名),左边是相应的类属性(作为k)

u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') 也就是字典 {'id':12345, 'name':'Michael', 'email': 'test@orm.org', 'password': 'my-pwd'} ,是要插入的行数据,其中id是类属性(作为k)







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值