zoukankan      html  css  js  c++  java
  • 通过ORM模型看python对象创建过程

    简易django ORM模型如下所示:

    #!/usr/bin/env python
    # encoding: utf-8
    """
    @version: 1.0
    @author: Pis
    @license: Apache Licence 
    @software: PyCharm
    @file: orm_test.py
    @time: 2018/5/9 9:52
    """
    
    #1
    class Field(object):
        def __init__(self, name, column_type):
            self.name = name
            self.column_type = column_type
    
        def __str__(self):
            return '<%s:%s>' % (self.__class__.__name__, self.name)
    
    #2
    class StringField(Field):
        def __init__(self, name):
            super(StringField, self).__init__(name, 'varchar(100)')
    
    #3
    class IntegerField(Field):
        def __init__(self, name):
            super(IntegerField, self).__init__(name, 'bigint')
    
    #4
    # 下一步,就是编写最复杂的ModelMetaclass了:
    class ModelMetaclass(type):
        def __new__(cls, name, bases, attrs):
            if name == 'Model':  # 排除掉对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):  # 如果找到一个Field属性,
                    print('Found mapping: %s ==> %s' % (k, v))
                    mappings[k] = v  # 就把它保存到一个__mappings__的dict中
            for k in mappings.keys():
                attrs.pop(k)  # 同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);
            attrs['__mappings__'] = mappings  # 保存属性和列的映射关系
            attrs['__table__'] = name  # 假设表名和类名一致  把表名保存到__table__中
            return type.__new__(cls, name, bases, attrs)
    
    #5
    # 基类Model
    class Model(dict, metaclass=ModelMetaclass):
        def __init__(self, **kw):
            super(Model, self).__init__(**kw)
    
        def __getattr__(self, item):  # 没有找到的属性,就在这里找
            try:
                return self[item]
            except KeyError:
                raise AttributeError(r"'Model' object has no attrs :'%s'" % item)
    
        def __setattr__(self, key, value):
            self[key] = value
    
        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))
    
        # 子类User
    
    #6 # 定义类的属性到列的映射: class User(Model): id = IntegerField('id') name = StringField('username') email = StringField('email') password = StringField('password') age = IntegerField('age')
    #7 if __name__ == "__main__": u = User(id=12345, name='john', email='123456789@qq.com', password='666666', height="top") u.age = 12 u.save()

     

    在代码执行过程中,在执行#7之前,首先是class的创建,在没有标明metaclass的情况下默认是由type通过__new__创建class对象,在标明了metaclass的情况下由metaclass的__new__方法创建(关于metaclass 的查找顺序上一篇给出【self,parents,local】),class创建完毕后才开始#7的执行,由于User类没有构造__new__和__init__方法,且User的父类Model继承了dict类,所以当height字段不在User的attrs时依然不会报错,实际上输入任何的关键字参数都不会出错。ORM模型在u.save()时,是通过查找在__new__时__map__中的字段,也就是#6中的(id,name,email,password,age),通过sql语句动态的执行存储操作。

  • 相关阅读:
    监控里的主码流和子码流是什么意思
    监控硬盘容量计算
    一个能让你了解所有函数调用顺序的Android库
    电工选线
    oracle linux dtrace
    list all of the Oracle 12c hidden undocumented parameters
    Oracle Extended Tracing
    window 驱动开发
    win7 x64 dtrace
    How to Use Dtrace Tracing Ruby Executing
  • 原文地址:https://www.cnblogs.com/MY0213/p/9012807.html
Copyright © 2011-2022 走看看