zoukankan      html  css  js  c++  java
  • python ORM 模块peewee(四): Model类源码初探

    Model的初始化方法主要继承自BaseModel类的__new__方法。 下面粗略的通过源码来看看:

    class BaseModel(type):
        # 定义可被继承的属性列表(全局)
        inheritable = set([
            'constraints', 'database', 'db_table_func', 'indexes', 'order_by',
            'primary_key', 'schema', 'validate_backrefs', 'only_save_dirty'])
    
        def __new__(cls, name, bases, attrs):
            # 如果没有父类,则之间创建BaseModel类
            if not bases:
                return super(BaseModel, cls).__new__(cls, name, bases, attrs)
    
            # Meta类的属性通过meta_options存储在Model类中
            meta_options = {}
            
            # 将Meta从属性中移除,将Meta中的非私有属性加入meta_options中
            meta = attrs.pop('Meta', None)
            if meta:
                for k, v in meta.__dict__.items():
                    if not k.startswith('_'):
                        meta_options[k] = v
    
            # 从meta中获取主键信息
            model_pk = getattr(meta, 'primary_key', None)
            parent_pk = None
    
            ############################################################
            # 开始考虑从父类中继承的情况
            #############################################################
            for b in bases:
                if not hasattr(b, '_meta'):
                    continue
    
                base_meta = getattr(b, '_meta')
                if parent_pk is None:
                    parent_pk = deepcopy(base_meta.primary_key)
                all_inheritable = cls.inheritable | base_meta._additional_keys
    
                # 获取父类中的Meta内部类字段,只考虑all_inheritable中的字段
                for (k, v) in base_meta.__dict__.items():
                    if k in all_inheritable and k not in meta_options:
                        meta_options[k] = v
                         
                # 获取父类中的Fields, 即表的字段
                for (k, v) in b.__dict__.items():
                    if k in attrs:
                        continue
                    if isinstance(v, FieldDescriptor):
                        if not v.field.primary_key:
                            attrs[k] = deepcopy(v.field)
    
            # initialize the new class and set the magic attributes
            cls = super(BaseModel, cls).__new__(cls, name, bases, attrs)
            ModelOptionsBase = meta_options.get('model_options_base', ModelOptions)
            cls._meta = ModelOptionsBase(cls, **meta_options)
            cls._data = None
            cls._meta.indexes = list(cls._meta.indexes)
    
            # 默认表名的设定,Model名的小写,然后将非数字和英文字符换成'_'
            if not cls._meta.db_table:
                cls._meta.db_table = re.sub('[^w]+', '_', cls.__name__.lower())
    
            # replace fields with field descriptors, calling the add_to_class hook
            # 这里筛选attr中的Field类型字段,设置Model中的数据类型
            # 也许可以测试一下类里面的函数是怎么继承的
            fields = []
            for name, attr in cls.__dict__.items():
                if isinstance(attr, Field):
                    if attr.primary_key and model_pk:
                        raise ValueError('primary key is overdetermined.')
                    elif attr.primary_key:
                        model_pk, pk_name = attr, name
                    else:
                        fields.append((attr, name))
            
            composite_key = False
            # 默认主键的设置,如果无法从父类继承,,则使用'id'为key, 也就是行号
            if model_pk is None:
                if parent_pk:
                    model_pk, pk_name = parent_pk, parent_pk.name
                else:
                    model_pk, pk_name = PrimaryKeyField(primary_key=True), 'id'
            elif isinstance(model_pk, CompositeKey):
                pk_name = '_composite_key'
                composite_key = True
    
            # 如果model本身有主键的情况
            if model_pk is not False:
                model_pk.add_to_class(cls, pk_name)
                cls._meta.primary_key = model_pk
                cls._meta.auto_increment = (
                    isinstance(model_pk, PrimaryKeyField) or
                    bool(model_pk.sequence))
                cls._meta.composite_key = composite_key
    
            # 设置Fields
            for field, name in fields:
                field.add_to_class(cls, name)
    
            # create a repr and error class before finalizing
            # __unicode__的设置
            if hasattr(cls, '__unicode__'):
                setattr(cls, '__repr__', lambda self: '<%s: %r>' % (
                    cls.__name__, self.__unicode__()))
    
            # 错误信息
            exc_name = '%sDoesNotExist' % cls.__name__
            exc_attrs = {'__module__': cls.__module__}
            exception_class = type(exc_name, (DoesNotExist,), exc_attrs)
            cls.DoesNotExist = exception_class
            cls._meta.prepared()
    
            if hasattr(cls, 'validate_model'):
                cls.validate_model()
    
            return cls
    
  • 相关阅读:
    Ubuntu18.04安装PHP7.3
    常用的正则表达式大全
    python实现感知机线性分类模型
    Python-基于向量机SVM的文本分类
    ssh远程登录命令简单实例
    js页面间通信方法(storage事件)(浏览器页面间通信方法)
    Node Sass could not find a binding for your current environment 解决办法
    git上传遇到 GitHub could not read Username 的解决办法
    Vue新手村之新手村概述
    Vue新手村任务之任务前言
  • 原文地址:https://www.cnblogs.com/noway-neway/p/5276527.html
Copyright © 2011-2022 走看看