def _initialize_model(cls, bases): cls._meta = _meta(cls, bases) cls._default_manager = cls if not cls._meta.abstract: from django.db.models.loading import register_models register_models(cls._meta.app_label, cls)
def __new__(cls, name, bases, attrs): # If this isn't a subclass of Model, don't do anything special. try: if not filter(lambda b: issubclass(b, Model), bases): return super(ModelBase, cls).__new__(cls, name, bases, attrs) except NameError: # 'Model' isn't defined yet, meaning we're looking at Django's own # Model class, defined below. return super(ModelBase, cls).__new__(cls, name, bases, attrs) # Create the class. new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) new_class.add_to_class('_meta', Options(attrs.pop('Meta', None))) new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})) # Build complete list of parents for base in bases: # TODO: Checking for the presence of '_meta' is hackish. if '_meta' in dir(base): new_class._meta.parents.append(base) new_class._meta.parents.extend(base._meta.parents) if getattr(new_class._meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] new_class._meta.app_label = model_module.__name__.split('.')[-2] # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) # Add Fields inherited from parents for parent in new_class._meta.parents: for field in parent._meta.fields: # Only add parent fields if they aren't defined for this class. try: new_class._meta.get_field(field.name) except FieldDoesNotExist: field.contribute_to_class(new_class, field.name) if getattr(new_class._meta, 'row_level_permissions', False): from django.contrib.auth.models import RowLevelPermission gen_rel = django.contrib.contenttypes.generic.GenericRelation(RowLevelPermission, object_id_field="model_id", content_type_field="model_ct") new_class.add_to_class("row_level_permissions", gen_rel) new_class._prepare() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first class for this model to register with the framework. There # should only be one class for each model, so we must always return the # registered version. return get_model(new_class._meta.app_label, name, False)
def __new__(cls, name, bases, attrs): """Creates a combined appengine and Django model. The resulting model will be known to both the appengine libraries and Django. """ if name == 'BaseModel': # This metaclass only acts on subclasses of BaseModel. return super(PropertiedClassWithDjango, cls).__new__(cls, name, bases, attrs) new_class = super(PropertiedClassWithDjango, cls).__new__(cls, name, bases, attrs) new_class._meta = ModelOptions(new_class) new_class.objects = ModelManager(new_class) new_class._default_manager = new_class.objects new_class.DoesNotExist = types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {}) m = get_model(new_class._meta.app_label, name, False) if m: return m register_models(new_class._meta.app_label, new_class) return get_model(new_class._meta.app_label, name, False)
def __new__(cls, name, bases, attrs): # If this isn't a subclass of Model, don't do anything special. try: parents = [b for b in bases if issubclass(b, Model)] if not parents: return super(ModelBase, cls).__new__(cls, name, bases, attrs) except NameError: # 'Model' isn't defined yet, meaning we're looking at Django's own # Model class, defined below. return super(ModelBase, cls).__new__(cls, name, bases, attrs) # Create the class. new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) new_class.add_to_class('_meta', Options(attrs.pop('Meta', None))) new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})) new_class.add_to_class('MultipleObjectsReturned', types.ClassType('MultipleObjectsReturned', (MultipleObjectsReturned, ), {})) # Build complete list of parents for base in parents: # Things without _meta aren't functional models, so they're # uninteresting parents. if hasattr(base, '_meta'): new_class._meta.parents.append(base) new_class._meta.parents.extend(base._meta.parents) if getattr(new_class._meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] new_class._meta.app_label = model_module.__name__.split('.')[-2] # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) # Add Fields inherited from parents for parent in new_class._meta.parents: for field in parent._meta.fields: # Only add parent fields if they aren't defined for this class. try: new_class._meta.get_field(field.name) except FieldDoesNotExist: field.contribute_to_class(new_class, field.name) new_class._prepare() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first class for this model to register with the framework. There # should only be one class for each model, so we must always return the # registered version. return get_model(new_class._meta.app_label, name, False)
def __init__(cls, name, bases, attrs): """Creates a combined appengine and Django model. The resulting model will be known to both the appengine libraries and Django. """ cls._meta = _meta(cls) cls._default_manager = cls old_init(cls, name, bases, attrs) from django.db.models.loading import register_models register_models(cls._meta.app_label, cls)
def __new__(cls, name, bases, attrs): # If this isn't a subclass of Model, don't do anything special. if name == 'Model' or not filter(lambda b: issubclass(b, Model), bases): return super(ModelBase, cls).__new__(cls, name, bases, attrs) # Create the class. new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) new_class.add_to_class('_meta', Options(attrs.pop('Meta', None))) new_class.add_to_class( 'DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist, ), {})) # Build complete list of parents for base in bases: # TODO: Checking for the presence of '_meta' is hackish. if '_meta' in dir(base): new_class._meta.parents.append(base) new_class._meta.parents.extend(base._meta.parents) model_module = sys.modules[new_class.__module__] if getattr(new_class._meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. new_class._meta.app_label = model_module.__name__.split('.')[-2] # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) # Add Fields inherited from parents for parent in new_class._meta.parents: for field in parent._meta.fields: # Only add parent fields if they aren't defined for this class. try: new_class._meta.get_field(field.name) except FieldDoesNotExist: field.contribute_to_class(new_class, field.name) new_class._prepare() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first class for this model to register with the framework. There # should only be one class for each model, so we must always return the # registered version. return get_model(new_class._meta.app_label, name, False)
def create_model_at_runtime(app_name, *model_classes): """creates a dynamic model for testing purposes. For technical details, see https://code.djangoproject.com/wiki/DynamicModels""" # TODO: django.db.models.base.ModelBase.__call__ actually calles register model # i.e.: when the class is declared, it is registered automatically (in 1.3) for model_cls in model_classes: try: model_cls.objects.count() except: style = color.no_style() cursor = connection.cursor() statements, pending = connection.creation.sql_create_model(model_cls, style) for sql in statements: try: cursor.execute(sql) except Exception as e: raise Exception('%s\nSQL was:\n%s' % (e, sql)) register_models(app_name, *model_classes)
def create_model_at_runtime(app_name, *model_classes): """creates a dynamic model for testing purposes. For technical details, see https://code.djangoproject.com/wiki/DynamicModels""" # TODO: django.db.models.base.ModelBase.__call__ actually calles register model # i.e.: when the class is declared, it is registered automatically (in 1.3) for model_cls in model_classes: try: model_cls.objects.count() except: style = color.no_style() cursor = connection.cursor() statements, pending = connection.creation.sql_create_model(model_cls, style) for sql in statements: try: cursor.execute(sql) except Exception as e: raise Exception("%s\nSQL was:\n%s" % (e, sql)) register_models(app_name, *model_classes)
def __new__(cls, name, bases, attrs): new_class = super(ModelBase, cls).__new__(cls, name, bases, attrs) new_class.objects.model = new_class new_class._default_manager.model = new_class meta = getattr(new_class, 'Meta') if getattr(meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] kwargs = {"app_label": model_module.__name__.split('.')[-2]} else: kwargs = {"app_label": meta.app_label} new_class._meta = Options(meta, **kwargs) new_class._meta.object_name = new_class.__name__ new_class._meta.module_name = new_class.__name__.lower() new_class._meta.concrete_model = new_class if not hasattr(new_class.Meta, "verbose_name"): new_class._meta.verbose_name = new_class.__name__.lower() if not hasattr(new_class.Meta, "verbose_name_plural"): new_class._meta.verbose_name_plural = new_class._meta.verbose_name + "s" class Pk(Field): name = "pk" attname = "id" new_class._meta.pk = Pk() new_class._meta.id = Pk() new_class._meta.id.name = "id" #new_class._meta.fields.append(new_class._meta.pk) #new_class._meta.fields.append(new_class._meta.id) for attr, attr_value in attrs.items(): if hasattr(attr_value, 'contribute_to_class'): attr_value.name = attr setattr(new_class, attr, None) attr_value.name = attr new_class._meta.fields.append(attr_value) new_class._deferred = False register_models(new_class._meta.app_label, new_class) return new_class
def generate_child_partition(parent, num): opts = parent._meta partition_name = '%s_Partition%s' % (parent.__name__, num) # HACK: Attempting to initialize a model twice results in a broken model # even though ModelBase is supposed to handle this case already. Instead, # we explicitly check to make sure the model wasn't created yet by # using get_model to prevent this case. app_label = parent._meta.app_label m = loading.get_model(app_label, partition_name, seed_cache=False) if m is not None: return m partition = ModelBase(partition_name, (parent,), { '__module__': parent.__module__, 'objects': Manager(), 'Meta': type('Meta', (object,), { 'managed': True, 'db_table': '%s_%s' % (parent._meta.db_table, num), 'unique_together': opts.unique_together, }), '_shards': ShardOptions(parent=parent, num=num), }) partition.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (parent.DoesNotExist,), parent.__module__)) partition.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', (parent.MultipleObjectsReturned,), parent.__module__)) # Connect signals so we can re-send them signaler = resend_signal(parent) for signal in (signals.pre_save, signals.post_save, signals.pre_delete, signals.post_delete, signals.pre_init, signals.post_init, signals.m2m_changed): signal.connect(signaler, sender=partition, weak=False) # Ensure the partition is available within the module scope module = sys.modules[parent.__module__] setattr(module, partition.__name__, partition) # Register all partitions with Django loading.register_models(app_label, partition) return partition
def get_adapted_model(other, field): global _ADAPTED_MODEL_COUNT # called by do_related_class, which is the first point we're # guarenteed to have the real model class of the relationship. # build a meta class for the object class Meta: app_label = other._meta.app_label proxy = True attrs = { '__module__': 'model_adapter', 'Meta': Meta, '__eq__': _overridden_equality_check, } # setup the properties for field_map = field.rel._field_map for attr_name, target_field in field_map.iteritems(): if callable(target_field): attrs[attr_name] = target_field else: attrs[attr_name] = AdaptiveDescriptor(attr_name, target_field) new_class = type(other._meta.object_name, (other,), attrs) # everything below is a complete hack to get the proxy to work correctly # our new proxy class just took over the real classes slot in django's # model registry. it shouldn't exist here, so purge it. app_model_registry = loading.cache.app_models[other._meta.app_label] del app_model_registry[other._meta.object_name.lower()] # and replace it with the original loading.register_models(other._meta.app_label, other) # and finally, so models validate, register the new class # with a unique name inside our own app. we need to do some # tricks with the new classes object_name, which is used in # the registration process obj_name = new_class._meta.object_name _ADAPTED_MODEL_COUNT += 1 new_class._meta.object_name = 'model-%s' % _ADAPTED_MODEL_COUNT loading.register_models('__model_adapter__', new_class) new_class._meta.object_name = obj_name return new_class
def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, ModelBase)] if not parents: # If this isn't a subclass of Model, don't do anything special. return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop('__module__') new_class = super_new(cls, name, bases, {'__module__': module}) attr_meta = attrs.pop('Meta', None) 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) if getattr(meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] kwargs = {"app_label": model_module.__name__.split('.')[-2]} else: kwargs = {} new_class.add_to_class('_meta', Options(meta, **kwargs)) if not abstract: new_class.add_to_class( 'DoesNotExist', subclass_exception( 'DoesNotExist', tuple(x.DoesNotExist for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (ObjectDoesNotExist, ), module)) new_class.add_to_class( 'MultipleObjectsReturned', subclass_exception( 'MultipleObjectsReturned', tuple(x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (MultipleObjectsReturned, ), module)) 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 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) # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) # All the fields of any type declared on this model new_fields = new_class._meta.local_fields + \ new_class._meta.local_many_to_many + \ new_class._meta.virtual_fields field_names = set([f.name for f in new_fields]) # Basic setup for proxy models. if is_proxy: base = None for parent in [cls for cls in parents if hasattr(cls, '_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) if (new_class._meta.local_fields or new_class._meta.local_many_to_many): raise FieldError("Proxy model '%s' contains model fields." % name) new_class._meta.setup_proxy(base) new_class._meta.concrete_model = base._meta.concrete_model else: new_class._meta.concrete_model = new_class # Do the appropriate setup for any model parents. o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields if isinstance(f, OneToOneField)]) 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: 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: # Concrete classes... base = base._meta.concrete_model if base in o2o_map: field = o2o_map[base] elif not is_proxy: attr_name = '%s_ptr' % base._meta.module_name field = OneToOneField(base, name=attr_name, auto_created=True, parent_link=True) new_class.add_to_class(attr_name, field) else: field = None new_class._meta.parents[base] = field else: # .. and abstract ones. for field in parent_fields: new_class.add_to_class(field.name, copy.deepcopy(field)) # Pass any non-abstract parent classes onto child. new_class._meta.parents.update(base._meta.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() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False)
def patch(): import django.contrib.sessions.models import models django.contrib.sessions.models.Session = models.Session django.contrib.sessions.models.SessionManager = models.SessionManager register_models('django.contrib.sessions', models.Session)
def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, ModelBase)] if not parents: # If this isn't a subclass of Model, don't do anything special. return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop('__module__') new_class = super_new(cls, name, bases, {'__module__': module}) attr_meta = attrs.pop('Meta', None) 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) if getattr(meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] kwargs = {"app_label": model_module.__name__.split('.')[-2]} else: kwargs = {} new_class.add_to_class('_meta', Options(meta, **kwargs)) if not abstract: new_class.add_to_class( 'DoesNotExist', subclass_exception('DoesNotExist', ObjectDoesNotExist, module)) new_class.add_to_class( 'MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', MultipleObjectsReturned, module)) 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 old_default_mgr = None if getattr(new_class, '_default_manager', None): # We have a parent who set the default manager. if new_class._default_manager.model._meta.abstract: old_default_mgr = new_class._default_manager new_class._default_manager = None # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in list(attrs.items()): new_class.add_to_class(obj_name, obj) # Do the appropriate setup for any model parents. o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields if isinstance(f, OneToOneField)]) for base in parents: if not hasattr(base, '_meta'): # Things without _meta aren't functional models, so they're # uninteresting parents. continue if not base._meta.abstract: if base in o2o_map: field = o2o_map[base] field.primary_key = True new_class._meta.setup_pk(field) else: attr_name = '%s_ptr' % base._meta.module_name field = OneToOneField(base, name=attr_name, auto_created=True, parent_link=True) new_class.add_to_class(attr_name, field) new_class._meta.parents[base] = field else: # The abstract base class case. names = set([ f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many ]) for field in base._meta.local_fields + base._meta.local_many_to_many: if field.name in 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 if old_default_mgr and not new_class._default_manager: new_class._default_manager = old_default_mgr._copy_to_model( new_class) new_class._prepare() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, False)
def patch(): import django.contrib.sites django.contrib.sites.models.Site = models.Site django.contrib.sites.models.SiteManager = models.SiteManager register_models('django.contrib.sites', models.Site)
def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, ModelBase)] if not parents: # If this isn't a subclass of Model, don't do anything special. return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop("__module__") new_class = super_new(cls, name, bases, {"__module__": module}) attr_meta = attrs.pop("Meta", None) 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) if getattr(meta, "app_label", None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] kwargs = {"app_label": model_module.__name__.split(".")[-2]} else: kwargs = {} new_class.add_to_class("_meta", Options(meta, **kwargs)) if not abstract: new_class.add_to_class("DoesNotExist", subclass_exception("DoesNotExist", ObjectDoesNotExist, module)) new_class.add_to_class( "MultipleObjectsReturned", subclass_exception("MultipleObjectsReturned", MultipleObjectsReturned, module), ) 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 if getattr(new_class, "_default_manager", None): new_class._default_manager = None # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) # Do the appropriate setup for any model parents. o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields if isinstance(f, OneToOneField)]) for base in parents: if not hasattr(base, "_meta"): # Things without _meta aren't functional models, so they're # uninteresting parents. continue # All the fields of any type declared on this model new_fields = ( new_class._meta.local_fields + new_class._meta.local_many_to_many + new_class._meta.virtual_fields ) field_names = set([f.name for f in new_fields]) if not base._meta.abstract: # Concrete classes... if base in o2o_map: field = o2o_map[base] field.primary_key = True new_class._meta.setup_pk(field) else: attr_name = "%s_ptr" % base._meta.module_name field = OneToOneField(base, name=attr_name, auto_created=True, parent_link=True) new_class.add_to_class(attr_name, field) new_class._meta.parents[base] = field else: # .. and abstract ones. # Check for clashes between locally declared fields and those # on the ABC. parent_fields = base._meta.local_fields + base._meta.local_many_to_many for field in parent_fields: if 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)) # Pass any non-abstract parent classes onto child. new_class._meta.parents.update(base._meta.parents) # Inherit managers from the abstract base classes. base_managers = base._meta.abstract_managers base_managers.sort() for _, mgr_name, manager in base_managers: val = getattr(new_class, mgr_name, None) if not val or val is manager: new_manager = manager._copy_to_model(new_class) new_class.add_to_class(mgr_name, new_manager) # 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() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, False)
def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, ModelBase)] if not parents: # If this isn't a subclass of Model, don't do anything special. return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop('__module__') new_class = super_new(cls, name, bases, {'__module__': module}) attr_meta = attrs.pop('Meta', None) 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) if getattr(meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] kwargs = {"app_label": model_module.__name__.split('.')[-2]} else: kwargs = {} new_class.add_to_class('_meta', Options(meta, **kwargs)) if not abstract: new_class.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', ObjectDoesNotExist, module)) new_class.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', MultipleObjectsReturned, module)) 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 old_default_mgr = None if getattr(new_class, '_default_manager', None): # We have a parent who set the default manager. if new_class._default_manager.model._meta.abstract: old_default_mgr = new_class._default_manager new_class._default_manager = None # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in list(attrs.items()): new_class.add_to_class(obj_name, obj) # Do the appropriate setup for any model parents. o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields if isinstance(f, OneToOneField)]) for base in parents: if not hasattr(base, '_meta'): # Things without _meta aren't functional models, so they're # uninteresting parents. continue if not base._meta.abstract: if base in o2o_map: field = o2o_map[base] field.primary_key = True new_class._meta.setup_pk(field) else: attr_name = '%s_ptr' % base._meta.module_name field = OneToOneField(base, name=attr_name, auto_created=True, parent_link=True) new_class.add_to_class(attr_name, field) new_class._meta.parents[base] = field else: # The abstract base class case. names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) for field in base._meta.local_fields + base._meta.local_many_to_many: if field.name in 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 if old_default_mgr and not new_class._default_manager: new_class._default_manager = old_default_mgr._copy_to_model(new_class) new_class._prepare() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, False)
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() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False) 非成员函数 -------- 辅助 __new__ def copy_managers(cls, base_managers): # This is in-place sorting of an Options attribute, but that's fine. base_managers.sort()
data = api.me() uid = data['id'] user = User(**data) user.save() try: user.token.delete() except Token.DoesNotExist: pass token.user = user token.save() return user class Token(oauth2.Token): expires = m.IntegerField() activated = m.BooleanField(default=False) class Meta: app_label = 'facebook' user = m.OneToOneField(User, null=True) from django.db.models.loading import register_models register_models('facebook', User, Token)
api = self.consumer.api(token=token) data = api.me() uid = data['id'] user = User(**data) user.save() try: user.token.delete() except Token.DoesNotExist: pass token.user = user token.save() return user class Token(oauth2.Token): expires = m.IntegerField() activated = m.BooleanField(default=False) class Meta: app_label = 'facebook' user = m.OneToOneField(User, null=True) from django.db.models.loading import register_models register_models('facebook', User, Token)
def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ # six.with_metaclass() inserts an extra class called 'NewBase' in the # inheritance tree: Model -> NewBase -> object. But the initialization # should be executed only once for a given model class. # attrs will never be empty for classes declared in the standard way # (ie. with the `class` keyword). This is quite robust. if name == 'NewBase' and attrs == {}: return super_new(cls, name, bases, attrs) # Also ensure initialization is only performed for subclasses of Model # (excluding Model class itself). parents = [b for b in bases if isinstance(b, ModelBase) and not (b.__name__ == 'NewBase' and b.__mro__ == (b, object))] if not parents: return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop('__module__') new_class = super_new(cls, name, bases, {'__module__': module}) attr_meta = attrs.pop('Meta', None) 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) if getattr(meta, 'app_label', None) is None: # Figure out the app_label by looking one level up from the package # or module named 'models'. If no such package or module exists, # fall back to looking one level up from the module this model is # defined in. # For 'django.contrib.sites.models', this would be 'sites'. # For 'geo.models.places' this would be 'geo'. model_module = sys.modules[new_class.__module__] package_components = model_module.__name__.split('.') package_components.reverse() # find the last occurrence of 'models' try: app_label_index = package_components.index(MODELS_MODULE_NAME) + 1 except ValueError: app_label_index = 1 kwargs = {"app_label": package_components[app_label_index]} else: kwargs = {} new_class.add_to_class('_meta', Options(meta, **kwargs)) 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) # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) # All the fields of any type declared on this model new_fields = new_class._meta.local_fields + \ new_class._meta.local_many_to_many + \ new_class._meta.virtual_fields field_names = set([f.name for f in new_fields]) # Basic setup for proxy models. if is_proxy: base = None for parent in [cls for cls in parents if hasattr(cls, '_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) if (new_class._meta.local_fields or new_class._meta.local_many_to_many): raise FieldError("Proxy model '%s' contains model fields." % name) new_class._meta.setup_proxy(base) new_class._meta.concrete_model = base._meta.concrete_model else: 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): parent_links[field.rel.to] = 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: 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: # Concrete classes... base = base._meta.concrete_model if base in parent_links: field = parent_links[base] elif not is_proxy: attr_name = '%s_ptr' % base._meta.model_name field = OneToOneField(base, name=attr_name, auto_created=True, parent_link=True) new_class.add_to_class(attr_name, field) else: field = None new_class._meta.parents[base] = field else: # .. and abstract ones. for field in parent_fields: new_class.add_to_class(field.name, copy.deepcopy(field)) # Pass any non-abstract parent classes onto child. new_class._meta.parents.update(base._meta.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() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False)
def __new__(cls, name, bases, attrs): # Force this model to be abstract as it's not a real table if 'Meta' not in attrs: is_abstract = False attrs['Meta'] = type('Meta', (object,), { 'abstract': True, }) else: is_abstract = getattr(attrs['Meta'], 'abstract', False) attrs['Meta'].abstract = True attrs['objects'] = MasterPartitionManager() new_cls = super(PartitionDescriptor, cls).__new__(cls, name, bases, attrs) attr_shardopts = attrs.pop('Shards', None) # HACK: non-abstract inheritance is not supported due to issues with metaclass # recursion if not any(b._shards.abstract if hasattr(b, '_shards') else True for b in bases): return new_cls if not attr_shardopts: shardopts = getattr(new_cls, 'Shards', None) else: shardopts = attr_shardopts base_shardopts = getattr(new_cls, '_shards', None) shards = [] new_cls.add_to_class('_shards', MasterShardOptions(shardopts, nodes=shards)) if base_shardopts: for k in DEFAULT_NAMES: if not hasattr(new_cls._shards, k): setattr(new_cls._shards, k, getattr(base_shardopts, k, None)) # We record the true abstract switch as part of _shards new_cls._shards.abstract = is_abstract if is_abstract: return new_cls # Some basic validation for k in DEFAULT_NAMES: if getattr(new_cls._shards, k, None) is None: raise ValidationError('Missing shard configuration value for %r on %r.' % (k, new_cls)) new_cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), new_cls.__module__)) new_cls.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', (MultipleObjectsReturned,), new_cls.__module__)) # Because we're an abstract model, we must also fake our own registration app_label = new_cls._meta.app_label loading.register_models(app_label, new_cls) new_cls._really_prepare() # We need to create a model for each partition instance which is assigned to the # appropriate table for n in xrange(new_cls._shards.num_shards): partition = generate_child_partition(new_cls, n) # Add to list of partitions for this master shards.append(partition) return new_cls
def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, ModelBase)] if not parents: # If this isn't a subclass of Model, don't do anything special. return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop('__module__') new_class = super_new(cls, name, bases, {'__module__': module}) attr_meta = attrs.pop('Meta', None) 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) if getattr(meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] kwargs = {"app_label": model_module.__name__.split('.')[-2]} else: kwargs = {} new_class.add_to_class('_meta', Options(meta, **kwargs)) if not abstract: new_class.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', tuple(x.DoesNotExist for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (ObjectDoesNotExist,), module)) new_class.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', tuple(x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (MultipleObjectsReturned,), module)) 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 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) # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) # All the fields of any type declared on this model new_fields = new_class._meta.local_fields + \ new_class._meta.local_many_to_many + \ new_class._meta.virtual_fields field_names = set([f.name for f in new_fields]) # Basic setup for proxy models. if is_proxy: base = None for parent in [cls for cls in parents if hasattr(cls, '_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) if (new_class._meta.local_fields or new_class._meta.local_many_to_many): raise FieldError("Proxy model '%s' contains model fields." % name) while base._meta.proxy: base = base._meta.proxy_for_model new_class._meta.setup_proxy(base) # Do the appropriate setup for any model parents. o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields if isinstance(f, OneToOneField)]) 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: 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: # Concrete classes... while base._meta.proxy: # Skip over a proxy class to the "real" base it proxies. base = base._meta.proxy_for_model if base in o2o_map: field = o2o_map[base] elif not is_proxy: attr_name = '%s_ptr' % base._meta.module_name field = OneToOneField(base, name=attr_name, auto_created=True, parent_link=True) new_class.add_to_class(attr_name, field) else: field = None new_class._meta.parents[base] = field else: # .. and abstract ones. for field in parent_fields: new_class.add_to_class(field.name, copy.deepcopy(field)) # Pass any non-abstract parent classes onto child. new_class._meta.parents.update(base._meta.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() register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, False)
def __new__(cls, name, bases, attrs): super_new = super(ModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, ModelBase)] if not parents: # If this isn't a subclass of Model, don't do anything special. return super_new(cls, name, bases, attrs) # Create the class. module = attrs.pop('__module__') new_class = super_new(cls, name, bases, {'__module__': module}) attr_meta = attrs.pop('Meta', None) abstract = getattr(attr_meta, 'abstract', False) mat_view = getattr(attr_meta, 'materialized_view', False) leaf = False if mat_view and abstract: raise TypeError("A model cannot be 'abstract' and 'materialized_view' at the same time.") if not attr_meta: meta = getattr(new_class, 'Meta', None) else: meta = attr_meta base_meta = getattr(new_class, '_meta', None) if getattr(meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. model_module = sys.modules[new_class.__module__] kwargs = {"app_label": model_module.__name__.split('.')[-2]} else: kwargs = {} new_class.add_to_class('_meta', Options(meta, **kwargs)) if not abstract: new_class.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', tuple(x.DoesNotExist for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (ObjectDoesNotExist,), module)) new_class.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', tuple(x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (MultipleObjectsReturned,), module)) if base_meta: if 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 if base_meta.materialized_view or base_meta.leaf or ( base_meta.db_view and base_meta.intermediate): if mat_view : raise TypeError('A materialized view cannot inherit from another') new_class._meta.leaf = True leaf = True # register the materialized_view base new_class._meta.mat_view_base = base_meta.concrete_model if base_meta.leaf: mat_view_base = base_meta.mat_view_base new_class._meta.mat_view_base = mat_view_base # turn the base into an intermediate view base_meta.db_view = True if base_meta._auto_db_table: base_meta.db_table = '%s_%s' % (base_meta.db_table, 'view') base_meta.intermediate = True base_meta.leaf = False base_meta.abstract = True if base_meta.concrete: base_model = mat_view_base._meta.leaf_ids[base_meta.leaf_id] # concrete views know about themselves... base_meta.leaves = {base_model: base_meta.leaf_id} base_meta.leaf_ids = {base_meta.leaf_id: base_model} else: base_meta.leaves = {} base_meta.leaf_ids = {} ctype_field = IntegerField(db_index=True) ctype_field.acquired = True base_meta.concrete_model.add_to_class('pgd_child_type', ctype_field) if base_meta.intermediate: new_class._meta.mat_view_base = base_meta.mat_view_base is_proxy = new_class._meta.proxy 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) # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False) if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) if mat_view: # add a pgd_child_type field to identify the model of each view row if 'pgd_child_type' in attrs: # pfff... bloody clever users... It's 2:06 AM now, I won't fix it pass ctype_field = IntegerField(db_index=True) ctype_field.acquired = True new_class.add_to_class('pgd_child_type', ctype_field) # add caches of the children new_class._meta.leaf_ids = {} new_class._meta.leaves = {} # All the fields of any type declared on this model new_fields = new_class._meta.local_fields + \ new_class._meta.local_many_to_many + \ new_class._meta.virtual_fields field_names = set([f.name for f in new_fields]) # Basic setup for proxy models. if is_proxy: base = None for parent in [cls for cls in parents if hasattr(cls, '_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) if (new_class._meta.local_fields or new_class._meta.local_many_to_many): raise FieldError("Proxy model '%s' contains model fields." % name) new_class._meta.setup_proxy(base) new_class._meta.concrete_model = base._meta.concrete_model else: new_class._meta.concrete_model = new_class # Do the appropriate setup for any model parents. o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields if isinstance(f, OneToOneField)]) if leaf: # Add all child fields on its materalized and intermediate views and mark them # acquired child_fields = new_class._meta.local_fields + new_class._meta.local_many_to_many for base in [c for c in new_class.__mro__ if hasattr(c, '_meta') and ( c._meta.intermediate or c._meta.materialized_view) ]: inserted = False for field in child_fields: if not getattr(field, 'acquired', False): inserted = True parent_field = copy.deepcopy(field) parent_field.acquired = True if base._meta.intermediate: parent_field.child_field = True base.add_to_class(field.name, parent_field) if inserted: # move pgd_child_type at last position on the parent ctype_field = base._meta.get_field_by_name('pgd_child_type')[0] base._meta.local_fields.remove(ctype_field) base._meta.local_fields.append(ctype_field) # invalidate field caches if hasattr(base._meta, '_field_cache'): del base._meta._field_cache del base._meta._field_name_cache if hasattr(base._meta, '_name_map'): del base._meta._name_map 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, except in mat. view inheritance). if not leaf: for field in parent_fields: 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: # Concrete classes... base = base._meta.concrete_model if base in o2o_map: field = o2o_map[base] elif not is_proxy: attr_name = '%s_ptr' % base._meta.module_name field = OneToOneField(base, name=attr_name, auto_created=True, parent_link=True) new_class.add_to_class(attr_name, field) else: field = None new_class._meta.parents[base] = field else: # .. and abstract ones. for field in parent_fields: if not getattr(field, 'acquired', False): new_class.add_to_class(field.name, copy.deepcopy(field)) # Pass any non-abstract parent classes onto child. new_class._meta.parents.update(base._meta.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() if mat_view: # now we know the table name, we can set the sequence name tname = new_class._meta.db_table new_class._meta.pk.sequence = tname + '_id_seq' register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. new_class = get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False) if mat_view: # turn it into an abstract model, so children won't try to create # joins new_class._meta.abstract = True # Now, we override new_class.__new__ on non-concrete intermediate and # materialized views to choose the class of the new object returned # when the user (or a QuerySet) tries to instantiate it. # It is chosen amongst leaves def new_matview_new(klass,*args,**kwargs): # leaf classes are not patched if not (klass._meta.materialized_view or klass._meta.intermediate): return Model.__new__(klass, *args, **kwargs) if len(kwargs) and klass._meta.concrete: # probably a user instanciation return Model.__new__(klass, *args, **kwargs) parent_fnames = [f.column for f in klass._meta.fields] idx = parent_fnames.index('pgd_child_type') if len(args) <= idx and 'pgd_child_type' not in kwargs: # I wouldn't do that if I were you. Seems like a smart (or # crazy) user is trying to do something clever (or foolish) # and I don't want to refrain one's creativity. This model # cannot be saved anyway. return Model.__new__(klass,*args,**kwargs) # Here is the magic: if you try to instanciate a m10d view # you get its subbclass corresponding to its pgd_child_type # That how mixed queryset work. # pgd_child_type should be the last field. Just to be sure leaf = klass._meta.leaf_ids.get(args[idx],None) # TODO PG: add an exception here if None # hook the __init__ arguments leaf_fnames = [f.name for f in leaf._meta.fields] leaf_args = [None]*len(leaf_fnames) for i in range(len(parent_fnames)): fname = parent_fnames[i] if fname in leaf_fnames: leaf_args[leaf_fnames.index(fname)] = args[i] inst = Model.__new__(leaf,*leaf_args,**kwargs) # The modified arg list is stored on the instance itself. # A hook in __init__ will send it to the original __init__ inst.__hooked_args__ = leaf_args return inst new_matview_new.__patched__ = True if not getattr(new_class.__new__, '__patched__', False): new_class.__new__ = staticmethod(new_matview_new) if leaf or (new_class._meta.intermediate and new_class._meta.concrete): # register the leaf on its materialized_view base model mvbase = new_class._meta.mat_view_base mvbase._meta.register_leaf(new_class) return new_class