class ModelBase(type): """ Metaclass for all models. """ def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ # Also ensure initialization is only performed for subclasses of Model # (excluding Model class itself). parents = [b for b in bases if isinstance(b, ModelBase)] if not parents: return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop('__module__')#model所在的文件 new_class = super_new(cls, name, bases, {'__module__': module}) attr_meta = attrs.pop('Meta', None)#内部类,生成option对象 abstract = getattr(attr_meta, 'abstract', False) if not attr_meta: meta = getattr(new_class, 'Meta', None) else: meta = attr_meta base_meta = getattr(new_class, '_meta', None) app_label = None # Look for an application configuration to attach the model to. app_config = apps.get_containing_app_config(module)#获取model所在的app配置 if getattr(meta, 'app_label', None) is None: if app_config is None: if not abstract: raise RuntimeError( "Model class %s.%s doesn't declare an explicit " "app_label and isn't in an application in " "INSTALLED_APPS." % (module, name) ) else: app_label = app_config.label#获取app标签 new_class.add_to_class('_meta', Options(meta, app_label))#生成_meta属性 if not abstract:#不是抽象类,加入两个异常属性 new_class.add_to_class( 'DoesNotExist', subclass_exception( str('DoesNotExist'), tuple( x.DoesNotExist for x in parents if hasattr(x, '_meta') and not x._meta.abstract ) or (ObjectDoesNotExist,), module, attached_to=new_class)) new_class.add_to_class( 'MultipleObjectsReturned', subclass_exception( str('MultipleObjectsReturned'), tuple( x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta') and not x._meta.abstract ) or (MultipleObjectsReturned,), module, attached_to=new_class)) if base_meta and not base_meta.abstract: # Non-abstract child classes inherit some attributes from their # non-abstract parent (unless an ABC comes before it in the # method resolution order). if not hasattr(meta, 'ordering'): new_class._meta.ordering = base_meta.ordering if not hasattr(meta, 'get_latest_by'): new_class._meta.get_latest_by = base_meta.get_latest_by is_proxy = new_class._meta.proxy # If the model is a proxy, ensure that the base class # hasn't been swapped out. if is_proxy and base_meta and base_meta.swapped: raise TypeError("%s cannot proxy the swapped model '%s'." % (name, base_meta.swapped)) if getattr(new_class, '_default_manager', None): if not is_proxy: # Multi-table inheritance doesn't inherit default manager from # parents. new_class._default_manager = None new_class._base_manager = None else: # Proxy classes do inherit parent's default manager, if none is # set explicitly. new_class._default_manager = new_class._default_manager._copy_to_model(new_class) new_class._base_manager = new_class._base_manager._copy_to_model(new_class) # Add all attributes to the class. for obj_name, obj in attrs.items():#添加fields,field如果是对象会调用自己的contribute_to_class方法 new_class.add_to_class(obj_name, obj) # All the fields of any type declared on this model new_fields = chain(#该model的所有field new_class._meta.local_fields, new_class._meta.local_many_to_many, new_class._meta.virtual_fields ) field_names = {f.name for f in new_fields}#{}生成field 名的set # Basic setup for proxy models. if is_proxy: base = None for parent in [kls for kls in parents if hasattr(kls, '_meta')]: if parent._meta.abstract: if parent._meta.fields: raise TypeError( "Abstract base class containing model fields not " "permitted for proxy model '%s'." % name ) else: continue if base is not None: raise TypeError("Proxy model '%s' has more than one non-abstract model base class." % name) else: base = parent if base is None: raise TypeError("Proxy model '%s' has no non-abstract model base class." % name) new_class._meta.setup_proxy(base) new_class._meta.concrete_model = base._meta.concrete_model base._meta.concrete_model._meta.proxied_children.append(new_class._meta) else:#设置非代理类的实体model,为model类名 new_class._meta.concrete_model = new_class # Collect the parent links for multi-table inheritance. parent_links = {}#多表继承的父链 for base in reversed([new_class] + parents): # Conceptually equivalent to `if base is Model`. if not hasattr(base, '_meta'): continue # Skip concrete parent classes. if base != new_class and not base._meta.abstract:#跳过实体父类 continue # Locate OneToOneField instances. for field in base._meta.local_fields: if isinstance(field, OneToOneField): related = resolve_relation(new_class, field.remote_field.model) parent_links[make_model_tuple(related)] = field # Do the appropriate setup for any model parents. for base in parents: original_base = base if not hasattr(base, '_meta'): # Things without _meta aren't functional models, so they're # uninteresting parents. continue parent_fields = base._meta.local_fields + base._meta.local_many_to_many # Check for clashes between locally declared fields and those # on the base classes (we cannot handle shadowed fields at the # moment). for field in parent_fields:#检查父类的field有无同名的,不能同名 if field.name in field_names: raise FieldError( 'Local field %r in class %r clashes ' 'with field of similar name from ' 'base class %r' % (field.name, name, base.__name__) ) if not base._meta.abstract:#父类是实体model # Concrete classes... base = base._meta.concrete_model base_key = make_model_tuple(base)#app,model_name if base_key in parent_links: field = parent_links[base_key] elif not is_proxy: attr_name = '%s_ptr' % base._meta.model_name#生成field为model_name+_ptr field = OneToOneField(#创建一个field base, on_delete=CASCADE, name=attr_name, auto_created=True, parent_link=True, ) # Only add the ptr field if it's not already present; # e.g. migrations will already have it specified if not hasattr(new_class, attr_name): new_class.add_to_class(attr_name, field) else: field = None new_class._meta.parents[base] = field#为类添加model_name+_ptr else: base_parents = base._meta.parents.copy() # .. and abstract ones. for field in parent_fields:#把抽象类的field添加到新类 new_field = copy.deepcopy(field) new_class.add_to_class(field.name, new_field) # Replace parent links defined on this base by the new # field as it will be appropriately resolved if required. if field.one_to_one: for parent, parent_link in base_parents.items(): if field == parent_link: base_parents[parent] = new_field # Pass any non-abstract parent classes onto child. new_class._meta.parents.update(base_parents) # Inherit managers from the abstract base classes. new_class.copy_managers(base._meta.abstract_managers) # Proxy models inherit the non-abstract managers from their base, # unless they have redefined any of them. if is_proxy: new_class.copy_managers(original_base._meta.concrete_managers) # Inherit virtual fields (like GenericForeignKey) from the parent # class for field in base._meta.virtual_fields: if base._meta.abstract and field.name in field_names: raise FieldError( 'Local field %r in class %r clashes ' 'with field of similar name from ' 'abstract base class %r' % (field.name, name, base.__name__) ) new_class.add_to_class(field.name, copy.deepcopy(field)) if abstract: # Abstract base models can't be instantiated and don't appear in # the list of models for an app. We do the final setup for them a # little differently from normal models. attr_meta.abstract = False new_class.Meta = attr_meta return new_class new_class._prepare() new_class._meta.apps.register_model(new_class._meta.app_label, new_class) '''print "new class:" print new_class.__dict__ print "new class meta:" print new_class._meta.__dict__''' return new_class
C:\>cd mez
C:\mez>python manage.py shell
Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)]
Type "copyright", "credits" or "license" for more information.
IPython 5.3.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
导入Page,Linkmodel,导入时就会生成这两个类
In [1]: from mezzanine.pages.models import Page,Link
页类的选项词典
In [2]: Page._meta.__dict__
Out[2]:
{'_get_fields_cache': {(True,
False,
False,
False,
True):
(<django.db.models.fields.AutoField: id>,
<django.db.models.fields.CharField: keywords_string>, <django.db.models.fields.related.ForeignKey: site>,
<django.db.models.fields.CharField: title>,
<django.db.models.fields.CharField: slug>,
<django.db.models.fields.CharField: _meta_title>,
<django.db.models.fields.TextField: description>,
<django.db.models.fields.BooleanField: gen_description>, <django.db.models.fields.DateTimeField: created>,
<django.db.models.fields.DateTimeField: updated>,
<django.db.models.fields.IntegerField: status>,
<django.db.models.fields.DateTimeField: publish_date>,
<django.db.models.fields.DateTimeField: expiry_date>,
<django.db.models.fields.URLField: short_url>,
<django.db.models.fields.BooleanField: in_sitemap>,
<mezzanine.core.fields.OrderField: _order>,
<django.db.models.fields.related.ForeignKey: parent>,
<mezzanine.pages.fields.MenusField: in_menus>,
<django.db.models.fields.CharField: titles>,
<django.db.models.fields.CharField: content_model>, <django.db.models.fields.BooleanField: login_required>, <mezzanine.generic.fields.KeywordsField: keywords>),
(True, False, True, False, False): (<django.db.models.fields.AutoField: id>,
<django.db.models.fields.CharField: keywords_string>,
<django.db.models.fields.related.ForeignKey: site>,
<django.db.models.fields.CharField: title>,
<django.db.models.fields.CharField: slug>,
<django.db.models.fields.CharField: _meta_title>,
<django.db.models.fields.TextField: description>,
<django.db.models.fields.BooleanField: gen_description>,
<django.db.models.fields.DateTimeField: created>,
<django.db.models.fields.DateTimeField: updated>,
<django.db.models.fields.IntegerField: status>,
<django.db.models.fields.DateTimeField: publish_date>,
<django.db.models.fields.DateTimeField: expiry_date>,
<django.db.models.fields.URLField: short_url>,
<django.db.models.fields.BooleanField: in_sitemap>,
<mezzanine.core.fields.OrderField: _order>,
<django.db.models.fields.related.ForeignKey: parent>,
<mezzanine.pages.fields.MenusField: in_menus>,
<django.db.models.fields.CharField: titles>,
<django.db.models.fields.CharField: content_model>,
<django.db.models.fields.BooleanField: login_required>),
(True, True, True, False, True): (<ManyToOneRel: pages.page>,
<OneToOneRel: pages.richtextpage>,
<OneToOneRel: pages.link>,
<OneToOneRel: forms.form>,
<OneToOneRel: galleries.gallery>,
<django.db.models.fields.AutoField: id>,
<django.db.models.fields.CharField: keywords_string>,
<django.db.models.fields.related.ForeignKey: site>,
<django.db.models.fields.CharField: title>,
<django.db.models.fields.CharField: slug>,
<django.db.models.fields.CharField: _meta_title>,
<django.db.models.fields.TextField: description>,
<django.db.models.fields.BooleanField: gen_description>,
<django.db.models.fields.DateTimeField: created>,
<django.db.models.fields.DateTimeField: updated>,
<django.db.models.fields.IntegerField: status>,
<django.db.models.fields.DateTimeField: publish_date>,
<django.db.models.fields.DateTimeField: expiry_date>,
<django.db.models.fields.URLField: short_url>,
<django.db.models.fields.BooleanField: in_sitemap>,
<mezzanine.core.fields.OrderField: _order>,
<django.db.models.fields.related.ForeignKey: parent>,
<mezzanine.pages.fields.MenusField: in_menus>,
<django.db.models.fields.CharField: titles>,
<django.db.models.fields.CharField: content_model>,
<django.db.models.fields.BooleanField: login_required>,
<mezzanine.generic.fields.KeywordsField: keywords>)},
'_ordering_clash': False,
u'_relation_tree': [<django.db.models.fields.related.ForeignKey: parent>,
<django.db.models.fields.related.OneToOneField: page_ptr>,
<django.db.models.fields.related.OneToOneField: page_ptr>,
<django.db.models.fields.related.OneToOneField: page_ptr>,
<django.db.models.fields.related.OneToOneField: page_ptr>],
'abstract': False,
'app_label': 'pages',
'apps': <django.apps.registry.Apps at 0x112bcb0>,
'auto_created': False,
'auto_field': <django.db.models.fields.AutoField: id>,
'concrete_model': mezzanine.pages.models.Page,
'db_table': u'pages_page',
'db_tablespace': '',
'default_permissions': (u'add', u'change', u'delete'),
'default_related_name': None,
'get_latest_by': None,
'has_auto_field': True,
'index_together': (),
'local_fields': [<django.db.models.fields.AutoField: id>,
<django.db.models.fields.CharField: keywords_string>,
<django.db.models.fields.related.ForeignKey: site>,
<django.db.models.fields.CharField: title>,
<django.db.models.fields.CharField: slug>,
<django.db.models.fields.CharField: _meta_title>,
<django.db.models.fields.TextField: description>,
<django.db.models.fields.BooleanField: gen_description>,
<django.db.models.fields.DateTimeField: created>,
<django.db.models.fields.DateTimeField: updated>,
<django.db.models.fields.IntegerField: status>,
<django.db.models.fields.DateTimeField: publish_date>,
<django.db.models.fields.DateTimeField: expiry_date>,
<django.db.models.fields.URLField: short_url>,
<django.db.models.fields.BooleanField: in_sitemap>,
<mezzanine.core.fields.OrderField: _order>,
<django.db.models.fields.related.ForeignKey: parent>,
<mezzanine.pages.fields.MenusField: in_menus>,
<django.db.models.fields.CharField: titles>,
<django.db.models.fields.CharField: content_model>,
<django.db.models.fields.BooleanField: login_required>],
'local_many_to_many': [],
'managed': True,
'managers': [(37, <mezzanine.pages.managers.PageManager at 0x1eec3b0>, True),
(38, <django.db.models.manager.Manager at 0x1eec6f0>, False)],
'model': mezzanine.pages.models.Page,
'model_name': 'page',
'object_name': 'Page',
'order_with_respect_to': None,
'ordering': (u'titles',),
'original_attrs': {u'ordering': (u'titles',),
u'verbose_name': <django.utils.functional.__proxy__ at 0x1ee2d30>,
u'verbose_name_plural': <django.utils.functional.__proxy__ at 0x1ee2d50>},
'parents': OrderedDict(),
'permissions': [],
'pk': <django.db.models.fields.AutoField: id>,
'proxied_children': [],
'proxy': False,
'proxy_for_model': None,
'related_fkey_lookups': [],
'required_db_features': [],
'required_db_vendor': None,
'select_on_save': False,
'swappable': None,
'unique_together': (),
'verbose_name': <django.utils.functional.__proxy__ at 0x1ee2d30>,
'verbose_name_plural': <django.utils.functional.__proxy__ at 0x1ee2d50>,
'virtual_fields': [<mezzanine.generic.fields.KeywordsField: keywords>]}
In [3]: Link._meta.__dict__
Out[3]:
{'_forward_fields_map': {'_meta_title': <django.db.models.fields.CharField: _met
a_title>,
'_order': <mezzanine.core.fields.OrderField: _order>,
'content_model': <django.db.models.fields.CharField: content_model>,
'created': <django.db.models.fields.DateTimeField: created>,
'description': <django.db.models.fields.TextField: description>,
'expiry_date': <django.db.models.fields.DateTimeField: expiry_date>,
'gen_description': <django.db.models.fields.BooleanField: gen_description>,
u'id': <django.db.models.fields.AutoField: id>,
'in_menus': <mezzanine.pages.fields.MenusField: in_menus>,
'in_sitemap': <django.db.models.fields.BooleanField: in_sitemap>,
'keywords': <mezzanine.generic.fields.KeywordsField: keywords>,
u'keywords_string': <django.db.models.fields.CharField: keywords_string>,
'login_required': <django.db.models.fields.BooleanField: login_required>,
u'page_ptr': <django.db.models.fields.related.OneToOneField: page_ptr>,
u'page_ptr_id': <django.db.models.fields.related.OneToOneField: page_ptr>,
'parent': <django.db.models.fields.related.ForeignKey: parent>,
u'parent_id': <django.db.models.fields.related.ForeignKey: parent>,
'publish_date': <django.db.models.fields.DateTimeField: publish_date>,
'short_url': <django.db.models.fields.URLField: short_url>,
'site': <django.db.models.fields.related.ForeignKey: site>,
u'site_id': <django.db.models.fields.related.ForeignKey: site>,
'slug': <django.db.models.fields.CharField: slug>,
'status': <django.db.models.fields.IntegerField: status>,
'title': <django.db.models.fields.CharField: title>,
'titles': <django.db.models.fields.CharField: titles>,
'updated': <django.db.models.fields.DateTimeField: updated>},
'_get_fields_cache': {(True,
False,
False,
False,
True): (<django.db.models.fields.related.OneToOneField: page_ptr>, <mezzanine
.generic.fields.KeywordsField: keywords>),
(True, False, True, False, True): (<django.db.models.fields.AutoField: id>,
<django.db.models.fields.CharField: keywords_string>,
<django.db.models.fields.related.ForeignKey: site>,
<django.db.models.fields.CharField: title>,
<django.db.models.fields.CharField: slug>,
<django.db.models.fields.CharField: _meta_title>,
<django.db.models.fields.TextField: description>,
<django.db.models.fields.BooleanField: gen_description>,
<django.db.models.fields.DateTimeField: created>,
<django.db.models.fields.DateTimeField: updated>,
<django.db.models.fields.IntegerField: status>,
<django.db.models.fields.DateTimeField: publish_date>,
<django.db.models.fields.DateTimeField: expiry_date>,
<django.db.models.fields.URLField: short_url>,
<django.db.models.fields.BooleanField: in_sitemap>,
<mezzanine.core.fields.OrderField: _order>,
<django.db.models.fields.related.ForeignKey: parent>,
<mezzanine.pages.fields.MenusField: in_menus>,
<django.db.models.fields.CharField: titles>,
<django.db.models.fields.CharField: content_model>,
<django.db.models.fields.BooleanField: login_required>,
<django.db.models.fields.related.OneToOneField: page_ptr>,
<mezzanine.generic.fields.KeywordsField: keywords>)},
'_ordering_clash': False,
u'_relation_tree': [],
'abstract': False,
'app_label': 'pages',
'apps': <django.apps.registry.Apps at 0x112bcb0>,
'auto_created': False,
'auto_field': None,
'concrete_model': mezzanine.pages.models.Link,
'db_table': u'pages_link',
'db_tablespace': '',
'default_permissions': (u'add', u'change', u'delete'),
'default_related_name': None,
'get_latest_by': None,
'has_auto_field': False,
'index_together': (),
'local_fields': [<django.db.models.fields.related.OneToOneField: page_ptr>],
'local_many_to_many': [],
'managed': True,
'managers': [(41, <mezzanine.pages.managers.PageManager at 0x1eecc30>, True),
(42, <django.db.models.manager.Manager at 0x1eecc10>, False)],
'model': mezzanine.pages.models.Link,
'model_name': 'link',
'object_name': 'Link',
'order_with_respect_to': None,
'ordering': (u'_order',),
'original_attrs': {u'ordering': (u'_order',),
u'verbose_name': <django.utils.functional.__proxy__ at 0x1eec450>,
u'verbose_name_plural': <django.utils.functional.__proxy__ at 0x1eec950>},
'parents': OrderedDict([(mezzanine.pages.models.Page,
<django.db.models.fields.related.OneToOneField: page_ptr>)]),
'permissions': [],
'pk': <django.db.models.fields.related.OneToOneField: page_ptr>,
'proxied_children': [],
'proxy': False,
'proxy_for_model': None,
'related_fkey_lookups': [],
'required_db_features': [],
'required_db_vendor': None,
'select_on_save': False,
'swappable': None,
'unique_together': (),
'verbose_name': <django.utils.functional.__proxy__ at 0x1eec450>,
'verbose_name_plural': <django.utils.functional.__proxy__ at 0x1eec950>,
'virtual_fields': [<mezzanine.generic.fields.KeywordsField: keywords>]}
浙公网安备 33010602011771号