def __new__(cls, name, bases, attrs): super_new = super(XmlModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, XmlModelBase)] 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) if not attr_meta: meta = getattr(new_class, 'Meta', None) else: meta = attr_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 = {} new_class.add_to_class('_meta', Options(meta, **kwargs)) 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)) # Bail out early if we have already created this class. m = get_xml_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) new_class._prepare() register_xml_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_xml_model(new_class._meta.app_label, name, False)
def _prepare(self): super(TenantModelBase, self)._prepare() if issubclass(self, TenantSpecificModel): for_tenant_model = self._for_tenant_model # Attach the tenant model concrete managers since they should # override the ones from abstract bases. managers = for_tenant_model._meta.concrete_managers for _, mgr_name, manager in managers: new_manager = manager._copy_to_model(self) new_manager.creation_counter = manager.creation_counter self.add_to_class(mgr_name, new_manager) # Since our declaration class is not one of our parents we must # make sure our exceptions extend his. for exception in self.exceptions: subclass = subclass_exception( str(exception), (getattr(self, exception), getattr(for_tenant_model, exception)), self.__module__, self, ) self.add_to_class(exception, subclass)
def obj_get(self, request=None, **kwargs): # MongoEngine exceptions are separate from Django exceptions, we combine them here try: return super(MongoEngineResource, self).obj_get(request, **kwargs) except self._meta.object_class.DoesNotExist, e: exp = base.subclass_exception('DoesNotExist', (self._meta.object_class.DoesNotExist, exceptions.ObjectDoesNotExist), self._meta.object_class.DoesNotExist.__module__) raise exp(*e.args)
def _prepare(self): super(TenantModelBase, self)._prepare() if issubclass(self, TenantSpecificModel): for_tenant_model = self._for_tenant_model # TODO: Remove when dropping support for Django < 1.10 if django.VERSION >= (1, 10): for mgr_name, manager in for_tenant_model._meta.managers_map.items(): new_manager = copy.copy(manager) new_manager.creation_counter = manager.creation_counter self.add_to_class(mgr_name, new_manager) else: for _, mgr_name, manager in for_tenant_model._meta.concrete_managers: new_manager = manager._copy_to_model(self) new_manager.creation_counter = manager.creation_counter self.add_to_class(mgr_name, new_manager) # Since our declaration class is not one of our parents we must # make sure our exceptions extend his. for exception in self.exceptions: subclass = subclass_exception( str(exception), (getattr(self, exception), getattr(for_tenant_model, exception)), self.__module__, self, ) self.add_to_class(exception, subclass)
def obj_get(self, request=None, **kwargs): # MongoEngine exceptions are separate from Django exceptions, we combine them here try: return super(MongoEngineResource, self).obj_get(request, **kwargs) except self._meta.object_class.DoesNotExist, e: exp = models_base.subclass_exception( 'DoesNotExist', (self._meta.object_class.DoesNotExist, exceptions.ObjectDoesNotExist), self._meta.object_class.DoesNotExist.__module__) raise exp(*e.args)
def obj_get(self, bundle, **kwargs): # MongoEngine exceptions are separate from Django exceptions, we combine them here try: return super(MongoEngineResource, self).obj_get(bundle=bundle, **kwargs) except self._meta.object_class.DoesNotExist as ex: exp = models_base.subclass_exception('DoesNotExist', (self._meta.object_class.DoesNotExist, exceptions.ObjectDoesNotExist), self._meta.object_class.DoesNotExist.__module__) raise exp(*ex.args) except queryset.DoesNotExist as ex: exp = models_base.subclass_exception('DoesNotExist', (queryset.DoesNotExist, exceptions.ObjectDoesNotExist), queryset.DoesNotExist.__module__) raise exp(*ex.args) except self._meta.object_class.MultipleObjectsReturned as ex: exp = models_base.subclass_exception('MultipleObjectsReturned', (self._meta.object_class.MultipleObjectsReturned, exceptions.MultipleObjectsReturned), self._meta.object_class.MultipleObjectsReturned.__module__) raise exp(*ex.args) except queryset.MultipleObjectsReturned as ex: exp = models_base.subclass_exception('MultipleObjectsReturned', (queryset.MultipleObjectsReturned, exceptions.MultipleObjectsReturned), queryset.MultipleObjectsReturned.__module__) raise exp(*ex.args) except mongoengine.ValidationError as ex: exp = models_base.subclass_exception('DoesNotExist', (queryset.DoesNotExist, exceptions.ObjectDoesNotExist), queryset.DoesNotExist.__module__) raise exp(*ex.args)
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 _prepare(self): super(TenantModelBase, self)._prepare() if issubclass(self, TenantSpecificModel): for_tenant_model = self._for_tenant_model # Attach the tenant model concrete managers since they should # override the ones from abstract bases. managers = for_tenant_model._meta.concrete_managers for _, mgr_name, manager in managers: new_manager = manager._copy_to_model(self) new_manager.creation_counter = manager.creation_counter self.add_to_class(mgr_name, new_manager) # Since our declaration class is not one of our parents we must # make sure our exceptions extend his. for exception in self.exceptions: self.add_to_class(exception, subclass_exception(str(exception), (getattr(self, exception), getattr(for_tenant_model, exception)), self.__module__, self ))
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__(mcs, name, bases, attrs, **kwargs): super_new = super().__new__ # Also ensure initialization is only performed for subclasses of Model # (excluding Model class itself). parents = [b for b in bases if isinstance(b, ModelMeta)] if not parents: return super_new(mcs, name, bases, attrs, **kwargs) # Create the class. module = attrs.pop('__module__') new_attrs = {'__module__': module} classcell = attrs.pop('__classcell__', None) if classcell is not None: new_attrs['__classcell__'] = classcell attr_meta = attrs.pop('Meta', None) # Pass all attrs without a (Django-specific) contribute_to_class() # method to type.__new__() so that they're properly initialized # (i.e. __set_name__()). contributable_attrs = {} for obj_name, obj in list(attrs.items()): if _has_contribute_to_class(obj): contributable_attrs[obj_name] = obj else: new_attrs[obj_name] = obj new_class = super_new(mcs, name, bases, new_attrs, **kwargs) abstract = getattr(attr_meta, 'abstract', False) meta = attr_meta or getattr(new_class, 'Meta', None) base_meta = getattr(new_class, '_meta', None) app_label = None new_class.add_to_class('_meta', Options(meta, app_label)) 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, attached_to=new_class)) 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, 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)) # Add remaining attributes (those with a contribute_to_class() method) # to the class. for obj_name, obj in contributable_attrs.items(): new_class.add_to_class(obj_name, obj) # All the fields of any type declared on this model new_fields = chain(new_class._meta.local_fields, new_class._meta.local_many_to_many, new_class._meta.private_fields) field_names = {f.name for f in new_fields} # Basic setup for proxy models. 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) and field.remote_field.parent_link: related = resolve_relation(new_class, field.remote_field.model) parent_links[make_model_tuple(related)] = field # Track fields inherited from base models. inherited_attributes = set() # Do the appropriate setup for any model parents. for base in new_class.mro(): if base not in parents or not hasattr(base, '_meta'): # Things without _meta aren't functional models, so they're # uninteresting parents. inherited_attributes.update(base.__dict__) continue parent_fields = base._meta.local_fields + base._meta.local_many_to_many if not base._meta.abstract: # Check for clashes between locally declared fields and those # on the base classes. for field in parent_fields: if field.name in field_names: raise FieldError( 'Local field %r in class %r clashes with field of ' 'the same name from base class %r.' % ( field.name, name, base.__name__, )) else: inherited_attributes.add(field.name) # Concrete classes... base = base._meta.concrete_model base_key = make_model_tuple(base) if base_key in parent_links: field = parent_links[base_key] elif not is_proxy: attr_name = '%s_ptr' % base._meta.model_name field = OneToOneField( base, on_delete=CASCADE, name=attr_name, auto_created=True, parent_link=True, ) if attr_name in field_names: raise FieldError( "Auto-generated field '%s' in class %r for " "parent_link to base class %r clashes with " "declared field of the same name." % ( attr_name, name, base.__name__, )) # 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 else: base_parents = base._meta.parents.copy() # Add fields from abstract base class if it wasn't overridden. for field in parent_fields: if (field.name not in field_names and field.name not in new_class.__dict__ and field.name not in inherited_attributes): 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. 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 private fields (like GenericForeignKey) from the parent # class for field in base._meta.private_fields: if field.name in field_names: if not base._meta.abstract: raise FieldError( 'Local field %r in class %r clashes with field of ' 'the same name from base class %r.' % ( field.name, name, base.__name__, )) else: field = copy.deepcopy(field) if not base._meta.abstract: field.mti_inherited = True new_class.add_to_class(field.name, field) # Copy indexes so that index names are unique when models extend an # abstract model. new_class._meta.indexes = [ copy.deepcopy(idx) for idx in new_class._meta.indexes ] new_class._prepare() return new_class
data.update({ 'resource_types': type_map.keys(), }) return data def obj_get(self, request=None, **kwargs): # MongoEngine exceptions are separate from Django exceptions, we combine them here try: return super(MongoEngineResource, self).obj_get(request, **kwargs) except self._meta.object_class.DoesNotExist, e: exp = base.subclass_exception('DoesNotExist', (self._meta.object_class.DoesNotExist, exceptions.ObjectDoesNotExist), self._meta.object_class.DoesNotExist.__module__) raise exp(*e.args) except queryset.DoesNotExist, e: exp = base.subclass_exception('DoesNotExist', (queryset.DoesNotExist, exceptions.ObjectDoesNotExist), queryset.DoesNotExist.__module__) raise exp(*e.args) except self._meta.object_class.MultipleObjectsReturned, e: exp = base.subclass_exception('MultipleObjectsReturned', (self._meta.object_class.MultipleObjectsReturned, exceptions.MultipleObjectsReturned), self._meta.object_class.MultipleObjectsReturned.__module__) raise exp(*e.args) except queryset.MultipleObjectsReturned, e: exp = base.subclass_exception('MultipleObjectsReturned', (queryset.MultipleObjectsReturned, exceptions.MultipleObjectsReturned), queryset.MultipleObjectsReturned.__module__) raise exp(*e.args) except mongoengine.ValidationError, e: exp = base.subclass_exception('DoesNotExist', (queryset.DoesNotExist, exceptions.ObjectDoesNotExist), queryset.DoesNotExist.__module__) raise exp(*e.args) def obj_update(self, bundle, request=None, **kwargs): if not bundle.obj or not getattr(bundle.obj, 'pk', None): try: bundle.obj = self.obj_get(request, **kwargs)
def __new__(cls, name, bases, attrs): new_class = super(BrushfireModelBase, cls).__new__(cls, name, bases, attrs) parents = [b for b in bases if isinstance(b, BrushfireModelBase)] module = attrs.pop('__module__') attr_meta = attrs.pop('Meta', None) if not attr_meta: meta = getattr(new_class, 'Meta', None) else: meta = attr_meta app_config = apps.get_containing_app_config(module) setattr(new_class, 'objects', BrushfireManager(new_class)) if getattr(meta, 'app_label', None): label = meta.app_label elif app_config: label = app_config.label else: label = '__NONE__' new_class.add_to_class('_meta', Options(meta, **{'app_label':label})) new_class.add_to_class( 'DoesNotExist', subclass_exception( str('DoesNotExist'), (ObjectDoesNotExist,), module, attached_to=new_class)) new_class.add_to_class( 'MultipleObjectsReturned', subclass_exception( str('MultipleObjectsReturned'), (MultipleObjectsReturned,), module, attached_to=new_class)) if new_class._meta.proxy: raise BrushfireException, "BrushfireModels proxies not allowed." # add attributes to class for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) new_fields = chain( 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} new_class._meta.concrete_model = new_class # Do the appropriate setup for any model parents. for base in parents: 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__) ) # 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)) # Keep this stuff last new_class._prepare() # ModelBase calls this, not sure what it does or if we need it here. Need to investigate further. #new_class._meta.apps.register_model(new_class._meta.app_label, new_class) return new_class
from billiard.serialization import find_nearest_pickleable_exception as fnpe from billiard.serialization import UnpickleableExceptionWrapper from billiard.serialization import get_pickleable_exception as gpe from celery import states from celery.backends.base import BaseBackend, KeyValueStoreBackend class wrapobject(object): def __init__(self, *args, **kwargs): self.args = args Oldstyle = types.ClassType("Oldstyle", (), {}) Unpickleable = subclass_exception("Unpickleable", KeyError, "foo.module") Impossible = subclass_exception("Impossible", object, "foo.module") Lookalike = subclass_exception("Lookalike", wrapobject, "foo.module") b = BaseBackend() class TestBaseBackendInterface(unittest.TestCase): def test_get_status(self): self.assertRaises(NotImplementedError, b.is_successful, "SOMExx-N0Nex1stant-IDxx-") def test_store_result(self): self.assertRaises(NotImplementedError, b.store_result, "SOMExx-N0nex1stant-IDxx-", 42, states.SUCCESS)
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', SemanticOptions(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)
class MongoEngineResource(resources.ModelResource): """ Adaptation of ``ModelResource`` to MongoEngine. """ __metaclass__ = MongoEngineModelDeclarativeMetaclass def dispatch_subresource(self, request, subresource_name, **kwargs): field = self.fields[subresource_name] resource = field.to_class(self._meta.api_name) return resource.dispatch(request=request, **kwargs) def base_urls(self): base = super(MongoEngineResource, self).base_urls() embedded_urls = [] embedded = ((name, obj) for name, obj in self.fields.iteritems() if isinstance(obj, fields.EmbeddedListField)) for name, obj in embedded: embedded_urls.extend(( urls.url( r"^(?P<resource_name>%s)/(?P<pk>\w[\w-]*)/(?P<subresource_name>%s)%s$" % (self._meta.resource_name, name, utils.trailing_slash()), self.wrap_view('dispatch_subresource'), {'request_type': 'list'}, name='api_dispatch_subresource_list', ), urls.url( r"^(?P<resource_name>%s)/(?P<pk>\w[\w-]*)/(?P<subresource_name>%s)/(?P<subresource_pk>\w[\w-]*)%s$" % (self._meta.resource_name, name, utils.trailing_slash()), self.wrap_view('dispatch_subresource'), {'request_type': 'detail'}, name='api_dispatch_subresource_detail', ), )) return embedded_urls + base def _reset_collection(self): """ Because MongoEngine creates collection connection when queryset object is initialized, we have to make sure that currently configured connection to database is really used. This happens for example in tests, where querysets are initialized as resource classes are imported, but then database connection is changed to test database. """ self._meta.queryset._document._collection = None self._meta.queryset._collection_obj = self._meta.queryset._document._get_collection( ) if hasattr(self._meta.queryset, '_reset_already_indexed'): self._meta.queryset._reset_already_indexed() def get_object_list(self, request): """ An ORM-specific implementation of ``get_object_list``. Returns a queryset that may have been limited by other overrides. """ self._reset_collection() return self._meta.queryset.clone() def _get_object_type(self, request): match = CONTENT_TYPE_RE.match(request.META.get('CONTENT_TYPE', '')) if match: return match.group(1) elif 'type' in request.GET: return request.GET.get('type') else: return None def _wrap_polymorphic(self, resource, fun): object_class = self._meta.object_class qs = self._meta.queryset base_fields = self.base_fields fields = self.fields try: self._meta.object_class = resource._meta.object_class self._meta.queryset = resource._meta.queryset self.base_fields = resource.base_fields.copy() self.fields = resource.fields.copy() if getattr(self._meta, 'prefer_polymorphic_resource_uri', False): if resource.get_resource_uri(): self._meta.resource_name = resource._meta.resource_name if getattr(self._meta, 'include_resource_type', True): self.base_fields['resource_type'] = base_fields[ 'resource_type'] self.fields['resource_type'] = fields['resource_type'] return fun() finally: self._meta.object_class = object_class self._meta.queryset = qs self.base_fields = base_fields self.fields = fields def _wrap_request(self, request, fun): type_map = getattr(self._meta, 'polymorphic', {}) if not type_map: return fun() object_type = self._get_object_type(request) if not object_type: # Polymorphic resources are enabled, but # nothing is passed, so set it to a default try: object_type = self._get_type_from_class( type_map, self._meta.object_class) except KeyError: raise tastypie_exceptions.BadRequest("Invalid object type.") if object_type not in type_map: raise tastypie_exceptions.BadRequest("Invalid object type.") resource = type_map[object_type](self._meta.api_name) # Optimization if resource._meta.object_class is self._meta.object_class: return fun() return self._wrap_polymorphic(resource, fun) def dispatch(self, request_type, request, **kwargs): # We process specially only requests with payload if not request.body: assert request.method.lower() not in ('put', 'post', 'patch'), request.method return super(MongoEngineResource, self).dispatch(request_type, request, **kwargs) assert request.method.lower() in ('put', 'post', 'patch'), request.method return self._wrap_request( request, lambda: super(MongoEngineResource, self).dispatch( request_type, request, **kwargs)) def get_schema(self, request, **kwargs): return self._wrap_request( request, lambda: super(MongoEngineResource, self).get_schema( request, **kwargs)) def _get_resource_from_class(self, type_map, cls): for resource in type_map.itervalues(): if resource._meta.object_class is cls: return resource raise KeyError(cls) def _get_type_from_class(self, type_map, cls): # As we are overriding self._meta.object_class we have to make sure # that we do not miss real match, so if self._meta.object_class # matches, we still check other items, otherwise we return immediately res = None for typ, resource in type_map.iteritems(): if resource._meta.object_class is cls: if resource._meta.object_class is self._meta.object_class: res = typ else: return typ if res is not None: return res else: raise KeyError(cls) def dehydrate_resource_type(self, bundle): type_map = getattr(self._meta, 'polymorphic', {}) if not type_map: return None return self._get_type_from_class(type_map, bundle.obj.__class__) def full_dehydrate(self, bundle, for_list=False): type_map = getattr(self._meta, 'polymorphic', {}) if not type_map: return super(MongoEngineResource, self).full_dehydrate(bundle, for_list) # Optimization if self._meta.object_class is bundle.obj.__class__: return super(MongoEngineResource, self).full_dehydrate(bundle, for_list) resource = self._get_resource_from_class( type_map, bundle.obj.__class__)(self._meta.api_name) return self._wrap_polymorphic( resource, lambda: super(MongoEngineResource, self).full_dehydrate( bundle, for_list)) def full_hydrate(self, bundle): # When updating objects, we want to force only updates of the same type, and object # should be completely replaced if type is changed, so we throw and exception here # to direct program logic flow (it is cached and replace instead of update is tried) if bundle.obj and self._meta.object_class is not bundle.obj.__class__: raise tastypie_exceptions.NotFound( "A document instance matching the provided arguments could not be found." ) bundle = super(MongoEngineResource, self).full_hydrate(bundle) # We redo check for required fields as Tastypie is not # reliable as it does checks in an inconsistent way # (https://github.com/toastdriven/django-tastypie/issues/491) for field_object in self.fields.itervalues(): if field_object.readonly or getattr(field_object, '_primary_key', False): continue if not field_object.attribute: continue # Tastypie also skips setting value if it is None, but this means # updates to None are ignored: this is not good as it hides invalid # PUT/PATCH REST requests (setting value to None which should fail # validation (field required) is simply ignored and value is left # as it is) # (https://github.com/toastdriven/django-tastypie/issues/492) # We hydrate field again only if existing value is not None if getattr(bundle.obj, field_object.attribute, None) is not None: value = NOT_HYDRATED # Tastypie also ignores missing fields in PUT, # so we check for missing field here # (https://github.com/toastdriven/django-tastypie/issues/496) if field_object.instance_name not in bundle.data: if field_object.has_default(): if callable(field_object.default): value = field_object.default() else: value = field_object.default # If it can be blank, we leave the field as it is, it was possibly already populated or it is not even necessary to be elif field_object.blank: pass else: value = None else: value = field_object.hydrate(bundle) if value is None: setattr(bundle.obj, field_object.attribute, None) if field_object.blank or field_object.null: continue # We are just trying to fix Tastypie here, for other "null" values # like [] and {} we leave to MongoEngine validate to catch them if getattr(bundle.obj, field_object.attribute, None) is None: raise tastypie_exceptions.ApiFieldError( "The '%s' field has no data and doesn't allow a default or null value." % field_object.instance_name) return bundle def build_schema(self): data = super(MongoEngineResource, self).build_schema() for field_name, field_object in self.fields.items(): # We process ListField specially here (and not use field's # build_schema) so that Tastypie's ListField can be used if isinstance(field_object, tastypie_fields.ListField): if getattr(field_object, 'field', None): data['fields'][field_name]['content'] = {} field_type = field_object.field.__class__.__name__.lower() if field_type.endswith('field'): field_type = field_type[:-5] data['fields'][field_name]['content']['type'] = field_type if field_object.field.__doc__: data['fields'][field_name]['content'][ 'help_text'] = trim(field_object.field.__doc__) if hasattr(field_object, 'build_schema'): data['fields'][field_name].update(field_object.build_schema()) type_map = getattr(self._meta, 'polymorphic', {}) if not type_map: return data data.update({ 'resource_types': type_map.keys(), }) return data def obj_get(self, bundle, **kwargs): # MongoEngine exceptions are separate from Django exceptions, we combine them here try: return super(MongoEngineResource, self).obj_get(bundle=bundle, **kwargs) except self._meta.object_class.DoesNotExist, e: exp = models_base.subclass_exception( 'DoesNotExist', (self._meta.object_class.DoesNotExist, exceptions.ObjectDoesNotExist), self._meta.object_class.DoesNotExist.__module__) raise exp(*e.args) except queryset.DoesNotExist, e: exp = models_base.subclass_exception( 'DoesNotExist', (queryset.DoesNotExist, exceptions.ObjectDoesNotExist), queryset.DoesNotExist.__module__) raise exp(*e.args)
def __new__(cls, name, bases, attrs): """ Exactly the same except the line with ``isinstance(b, ROAModelBase)``. """ 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, ROAModelBase) 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. # 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(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 # 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.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)
return data def obj_get(self, request=None, **kwargs): # MongoEngine exceptions are separate from Django exceptions, we combine them here try: return super(MongoEngineResource, self).obj_get(request, **kwargs) except self._meta.object_class.DoesNotExist, e: exp = models_base.subclass_exception( 'DoesNotExist', (self._meta.object_class.DoesNotExist, exceptions.ObjectDoesNotExist), self._meta.object_class.DoesNotExist.__module__) raise exp(*e.args) except queryset.DoesNotExist, e: exp = models_base.subclass_exception( 'DoesNotExist', (queryset.DoesNotExist, exceptions.ObjectDoesNotExist), queryset.DoesNotExist.__module__) raise exp(*e.args) except self._meta.object_class.MultipleObjectsReturned, e: exp = models_base.subclass_exception( 'MultipleObjectsReturned', (self._meta.object_class.MultipleObjectsReturned, exceptions.MultipleObjectsReturned), self._meta.object_class.MultipleObjectsReturned.__module__) raise exp(*e.args) except queryset.MultipleObjectsReturned, e: exp = models_base.subclass_exception( 'MultipleObjectsReturned', (queryset.MultipleObjectsReturned, exceptions.MultipleObjectsReturned), queryset.MultipleObjectsReturned.__module__)
def _new_old_django(cls, name, bases, attrs): """ Exactly the same except the line with ``isinstance(b, ROAModelBase)`` and part delimited by 'ROA HACK' """ 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, ROAModelBase) 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. # 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: # ROA HACK: subclass_kwargs = { 'name': str('DoesNotExist'), 'parents': tuple(x.DoesNotExist for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (ObjectDoesNotExist, ), 'module': module } if DJANGO_GT_1_4: subclass_kwargs['attached_to'] = new_class new_class.add_to_class('DoesNotExist', subclass_exception(**subclass_kwargs)) subclass_kwargs = { 'name': str('MultipleObjectsReturned'), 'parents': tuple(x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta') and not x._meta.abstract) or (MultipleObjectsReturned, ), 'module': module } if DJANGO_GT_1_4: subclass_kwargs['attached_to'] = new_class new_class.add_to_class('MultipleObjectsReturned', subclass_exception(**subclass_kwargs)) # END HACK 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 # 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.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): super_new = super(XmlModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, XmlModelBase)] 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) if not attr_meta: meta = getattr(new_class, 'Meta', None) else: meta = attr_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 = {} for attr_name in DEFAULT_NAMES: if attr_name == 'app_label': continue if getattr(meta, attr_name, None) is None: for base in parents: if not hasattr(base, '_meta'): continue attr_val = getattr(base._meta, attr_name) if attr_val is not None: kwargs[attr_name] = attr_val break new_class.add_to_class('_meta', Options(meta, **kwargs)) new_class.add_to_class( 'DoesNotExist', subclass_exception( 'DoesNotExist', tuple(x.DoesNotExist for x in parents if hasattr(x, '_meta')) or (ObjectDoesNotExist, ), module)) new_class.add_to_class( 'MultipleObjectsReturned', subclass_exception( 'MultipleObjectsReturned', tuple(x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta')) or (MultipleObjectsReturned, ), module)) # Bail out early if we have already created this class. m = get_xml_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) field_names = set([f.name for f in new_class._meta.local_fields]) for base in parents: if not hasattr(base, '_meta'): # Things without _meta aren't functional models, so they're # uninteresting parents continue for field in base._meta.local_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__)) new_class.add_to_class(field.name, copy.deepcopy(field)) new_class._meta.parents.update(base._meta.parents) new_class._prepare() register_xml_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_xml_model(new_class._meta.app_label, name, False)
def patched_new(cls, name, bases, attrs): "Patched version of __new__" 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__') 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) # Look for an application configuration to attach the model to. app_config = apps.get_containing_app_config(module) if getattr(meta, 'app_label', None) is None: if app_config is None: # If the model is imported before the configuration for its # application is created (#21719), or isn't in an installed # application (#21680), use the legacy logic to 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'. if abstract: kwargs = {"app_label": None} else: msg = ( "Model class %s.%s doesn't declare an explicit app_label " "and either isn't in an application in INSTALLED_APPS or " "else was imported before its application was loaded. " % (module, name)) raise RuntimeError(msg) 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) # 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 [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: # patch while parent._meta.proxy: # patch parent = parent._meta.proxy_for_model # patch if base is not None and base is not parent: # patch 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 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) # 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 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() new_class._meta.apps.register_model(new_class._meta.app_label, new_class) return new_class
def __new__(cls, name, bases, attrs): super_new = super(XmlModelBase, cls).__new__ parents = [b for b in bases if isinstance(b, XmlModelBase)] 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) if not attr_meta: meta = getattr(new_class, 'Meta', None) else: meta = attr_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 = {} for attr_name in DEFAULT_NAMES: if attr_name == 'app_label': continue if getattr(meta, attr_name, None) is None: for base in parents: if not hasattr(base, '_meta'): continue attr_val = getattr(base._meta, attr_name) if attr_val is not None: kwargs[attr_name] = attr_val break new_class.add_to_class('_meta', Options(meta, **kwargs)) new_class.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', tuple(x.DoesNotExist for x in parents if hasattr(x, '_meta')) or (ObjectDoesNotExist,), module)) new_class.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', tuple(x.MultipleObjectsReturned for x in parents if hasattr(x, '_meta')) or (MultipleObjectsReturned,), module)) # Bail out early if we have already created this class. m = get_xml_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) field_names = set([f.name for f in new_class._meta.local_fields]) for base in parents: if not hasattr(base, '_meta'): # Things without _meta aren't functional models, so they're # uninteresting parents continue for field in base._meta.local_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__)) new_class.add_to_class(field.name, copy.deepcopy(field)) new_class._meta.parents.update(base._meta.parents) new_class._prepare() register_xml_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_xml_model(new_class._meta.app_label, name, False)