def __get__(self, inst, owner): value = super(ListField, self).__get__(inst, owner) MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): ReferenceField = _import('pymodm.fields.ReferenceField') if isinstance(self._field, ReferenceField): # Modify list in-place to avoid invalidating existing refs. value[:] = self.to_python(value)[:] if not self.is_blank(value): self.__set__(inst, value) return value
def __get__(self, instance, cls): """Only let Manager be accessible from Model classes.""" TopLevelMongoModel = _import('pymodm.base.models.TopLevelMongoModel') if isinstance(instance, TopLevelMongoModel): raise AttributeError( "Manager isn't accessible via %s instances." % (cls.__name__,)) return self
def __iter__(self): if self._return_raw: return self._get_raw_cursor() to_instance = self._model.from_document if self._select_related_fields is not None: dereference = _import('pymodm.dereference.dereference') to_instance = lambda doc: dereference( self._model.from_document(doc), self._select_related_fields) return (to_instance(doc) for doc in self._get_raw_cursor())
def related_model(self): if not self.__related_model: MongoModelBase = _import('pymodm.base.models.MongoModelBase') if isinstance(self.__model, string_types): self.__related_model = get_document(self.__model) # 'issubclass' complains if first argument is not a class. elif (isinstance(self.__model, type) and issubclass(self.__model, MongoModelBase)): self.__related_model = self.__model return self.__related_model
def delete(self): """Delete objects matched by this QuerySet. :returns: The number of documents deleted. """ ReferenceField = _import('pymodm.fields.ReferenceField') if self._model._mongometa.delete_rules: # Don't apply any delete rules if no documents match. if not self.count(): return 0 # Use values() to avoid overhead converting to Model instances. refs = [doc['_id'] for doc in self.values()] # Check for DENY rules before anything else. for rule_entry in self._model._mongometa.delete_rules: related_model, related_field = rule_entry rule = self._model._mongometa.delete_rules[rule_entry] if ReferenceField.DENY == rule: related_qs = related_model._mongometa.default_manager.raw( {related_field: {'$in': refs}}).values() if related_qs.count() > 0: raise errors.OperationError( 'Cannot delete a %s object while a %s object ' 'refers to it through its "%s" field.' % (self._model._mongometa.object_name, related_model._mongometa.object_name, related_field)) # If we've made it this far, it's ok to delete the objects in this # QuerySet. result = self._collection.delete_many( self._query, collation=self._collation).deleted_count # Apply the rest of the delete rules. for rule_entry in self._model._mongometa.delete_rules: related_model, related_field = rule_entry rule = self._model._mongometa.delete_rules[rule_entry] if ReferenceField.DO_NOTHING == rule: continue related_qs = (related_model._mongometa.default_manager .raw({related_field: {'$in': refs}}) .values()) if ReferenceField.NULLIFY == rule: related_qs.update({'$unset': {related_field: None}}) elif ReferenceField.CASCADE == rule: related_qs.delete() elif ReferenceField.PULL == rule: related_qs.update({'$pull': {related_field: {'$in': refs}}}) return result return self._collection.delete_many( self._query, collation=self._collation).deleted_count
def dereference_if_needed(self, value): # Already dereferenced values can be returned immediately. if isinstance(value, self.related_model): return value # Attempt to dereference the value as an id. if self.model._mongometa._auto_dereference: dereference_id = _import('pymodm.dereference.dereference_id') return dereference_id(self.related_model, value) return self.related_model._mongometa.pk.to_python(value)
def to_python(self, value): if isinstance(value, dict): # Try to convert the value into our document type. return self.related_model.from_document(value) elif isinstance(value, self.related_model): return value elif self.model._mongometa._auto_dereference: # Attempt to dereference the value as an id. dereference_id = _import('pymodm.dereference.dereference_id') return dereference_id(self.related_model, value) return value
def __get__(self, inst, owner): MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): raw_value = inst._data.get(self.attname, self.default) if self.is_blank(raw_value): return raw_value python = self.to_python(raw_value) # Cache retrieved value. self.__set__(inst, python) return python return self
def __get__(self, inst, owner): MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): raw_value = inst._data.get(self.attname, self.get_default()) if self.is_blank(raw_value): return raw_value # Cache pythonized value. python_value = self.to_python(raw_value) self.__set__(inst, python_value) return python_value # Access from outside a Model instance. return self
def __get__(self, inst, owner): MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): raw_value = inst._data.get(self.attname, self.default) if self.is_blank(raw_value): return raw_value # Cache pythonized value. python_value = self.to_python(raw_value) self.__set__(inst, python_value) return python_value # Access from outside a Model instance. return self
def __get__(self, inst, owner): MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): try: value = inst._data.get_python_value( self.attname, self.to_python) except KeyError: value = self._get_default_once(inst) if not self.is_blank(value): self.__set__(inst, value) return value return self
def __get__(self, inst, owner): MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): try: value = inst._data.get_python_value(self.attname, self.to_python) except KeyError: value = self._get_default_once(inst) if not self.is_blank(value): self.__set__(inst, value) return value return self
def __get__(self, inst, owner): MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): raw_value = inst._data.get(self.attname, self.default) if self.is_blank(raw_value): return raw_value # Turn whatever value we have into a FieldFile instance. _file = self._to_field_file(inst._data[self.attname], inst) # Store this transformed value back into the instance. inst._data[self.attname] = _file return self.to_python(_file) # Access from outside a Model instance. return self
def __init__(self, model, verbose_name=None, mongo_name=None, **kwargs): super(RelatedModelFieldsBase, self).__init__(verbose_name=verbose_name, mongo_name=mongo_name, **kwargs) self.__model = model self.__related_model = None MongoModelBase = _import('pymodm.base.models.MongoModelBase') if not (isinstance(model, string_types) or (isinstance(model, type) and issubclass(model, MongoModelBase))): raise ValueError('model must be a Model class or a string, not %s' % model.__class__.__name__)
def __init__(self, model, verbose_name=None, mongo_name=None, **kwargs): super(RelatedModelFieldsBase, self).__init__(verbose_name=verbose_name, mongo_name=mongo_name, **kwargs) self.__model = model self.__related_model = None MongoModelBase = _import('pymodm.base.models.MongoModelBase') if not (isinstance(model, string_types) or (isinstance(model, type) and issubclass(model, MongoModelBase))): raise ValueError( 'model must be a Model class or a string, not %s' % model)
def bulk_create(self, object_or_objects, retrieve=False, full_clean=False, ordered=True): """Save Model instances in bulk. :parameters: - `object_or_objects`: A list of MongoModel instances or a single instance. - `retrieve`: Whether to return the saved MongoModel instances. If ``False`` (the default), only the ids will be returned. - `full_clean`: Whether to validate each object by calling the :meth:`~pymodm.MongoModel.full_clean` method before saving. This isn't done by default. - `ordered` (optional): If ``True`` (the default) documents will be inserted on the server serially, in the order provided. If an error occurs all remaining inserts are aborted. If ``False``, documents will be inserted on the server in arbitrary order, possibly in parallel, and all document inserts will be attempted. :returns: A list of ids for the documents saved, or of the :class:`~pymodm.MongoModel` instances themselves if `retrieve` is ``True``. example:: >>> vacation_ids = Vacation.objects.bulk_create([ ... Vacation(destination='TOKYO', travel_method='PLANE'), ... Vacation(destination='ALGIERS', travel_method='PLANE')]) >>> print(vacation_ids) [ObjectId('578926716e32ab1d6a8dc718'), ObjectId('578926716e32ab1d6a8dc719')] """ retrieve = validate_boolean('retrieve', retrieve) full_clean = validate_boolean('full_clean', full_clean) TopLevelMongoModel = _import('pymodm.base.models.TopLevelMongoModel') if isinstance(object_or_objects, TopLevelMongoModel): object_or_objects = [object_or_objects] object_or_objects = validate_list_or_tuple('object_or_objects', object_or_objects) if full_clean: for object in object_or_objects: object.full_clean() docs = (obj.to_son() for obj in object_or_objects) ids = self._collection.insert_many(docs, ordered=ordered).inserted_ids if retrieve: return list(self.raw({'_id': {'$in': ids}})) return ids
def __init__(self, model, on_delete=DO_NOTHING, verbose_name=None, mongo_name=None, **kwargs): """ :parameters: - `model`: The class of :class:`~pymodm.MongoModel` that this field references or the name of the model as a string. - `on_delete`: The action to take (if any) when the referenced object is deleted. The delete rule should be one of the following: * :attr:`ReferenceField.DO_NOTHING` (default). * :attr:`ReferenceField.NULLIFY` * :attr:`ReferenceField.CASCADE` * :attr:`ReferenceField.DENY` * :attr:`ReferenceField.PULL` - `verbose_name`: A human-readable name for the Field. - `mongo_name`: The name of this field when stored in MongoDB. .. seealso:: constructor for :class:`~pymodm.base.fields.MongoBaseField` example:: class User(MongoModel): name = fields.CharField() # Reference the current model by passing the name as a string. friend = fields.ReferenceField('User') class Post(MongoModel): title = fields.CharField() author = fields.ReferenceField(User) .. seealso:: :ref:`GettingStartedReferenceExample`. """ super(ReferenceField, self).__init__(model=model, verbose_name=verbose_name, mongo_name=mongo_name, **kwargs) TopLevelMongoModel = _import('pymodm.base.models.TopLevelMongoModel') if (ReferenceField.DO_NOTHING != on_delete and not (isinstance(model, type) and issubclass(model, TopLevelMongoModel))): raise ValueError( 'Cannot specify on_delete without providing a Model class ' 'for model (was: %r). For bidirectional delete rules, ' 'use MyModelClass.register_delete_rule instead.' % model) self._on_delete = on_delete self.validators.append(validators.validator_for_func(self.to_mongo))
def __init__(self, model, verbose_name=None, mongo_name=None, **kwargs): super(RelatedEmbeddedModelFieldsBase, self).__init__(model=model, verbose_name=verbose_name, mongo_name=mongo_name, **kwargs) self.__model = model self.__related_model = None EmbeddedMongoModel = _import('pymodm.base.models.EmbeddedMongoModel') if not (isinstance(model, string_types) or (isinstance(model, type) and issubclass(model, EmbeddedMongoModel))): raise ValueError('model must be a EmbeddedMongoModel class or a ' 'string, not %s' % model)
def __init__(self, model, on_delete=DO_NOTHING, verbose_name=None, mongo_name=None, **kwargs): """ :parameters: - `model`: The class of :class:`~pymodm.MongoModel` that this field references. - `on_delete`: The action to take (if any) when the referenced object is deleted. The delete rule should be one of the following: - `verbose_name`: A human-readable name for the Field. - `mongo_name`: The name of this field when stored in MongoDB. * :attr:`ReferenceField.DO_NOTHING` (default). * :attr:`ReferenceField.NULLIFY` * :attr:`ReferenceField.CASCADE` * :attr:`ReferenceField.DENY` * :attr:`ReferenceField.PULL` .. seealso:: constructor for :class:`~pymodm.base.fields.MongoBaseField` """ super(ReferenceField, self).__init__(model=model, verbose_name=verbose_name, mongo_name=mongo_name, **kwargs) MongoModel = _import('pymodm.base.models.MongoModel') if (ReferenceField.DO_NOTHING != on_delete and not (isinstance(model, type) and issubclass(model, MongoModel))): raise ValueError( 'Cannot specify on_delete without providing a Model class ' 'for model (was: %r). For bidirectional delete rules, ' 'use MyModelClass.register_delete_rule instead.' % model) self._on_delete = on_delete self._is_instance = False def validate_related_model(ref): """Given a Model, verify that it's been saved first.""" if isinstance(ref, self.related_model) and not ref.pk: raise ValidationError( 'Referenced documents must be saved to the database first.') self.validators.append(validate_related_model)
def bulk_create(self, object_or_objects, retrieve=False, full_clean=False): """Save Model instances in bulk. :parameters: - `object_or_objects`: A list of MongoModel instances or a single instance. - `retrieve`: Whether to return the saved MongoModel instances. If ``False`` (the default), only the ids will be returned. - `full_clean`: Whether to validate each object by calling the :meth:`~pymodm.MongoModel.full_clean` method before saving. This isn't done by default. :returns: A list of ids for the documents saved, or of the :class:`~pymodm.MongoModel` instances themselves if `retrieve` is ``True``. example:: >>> vacation_ids = Vacation.objects.bulk_create([ ... Vacation(destination='TOKYO', travel_method='PLANE'), ... Vacation(destination='ALGIERS', travel_method='PLANE')]) >>> print(vacation_ids) [ObjectId('578926716e32ab1d6a8dc718'), ObjectId('578926716e32ab1d6a8dc719')] """ retrieve = validate_boolean('retrieve', retrieve) full_clean = validate_boolean('full_clean', full_clean) TopLevelMongoModel = _import('pymodm.base.models.TopLevelMongoModel') if isinstance(object_or_objects, TopLevelMongoModel): object_or_objects = [object_or_objects] object_or_objects = validate_list_or_tuple( 'object_or_objects', object_or_objects) if full_clean: for object in object_or_objects: object.full_clean() docs = (obj.to_son() for obj in object_or_objects) ids = self._collection.insert_many(docs).inserted_ids if retrieve: return list(self.raw({'_id': {'$in': ids}})) return ids
def __get__(self, inst, owner): MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): if self.storage is None: gridfs = GridFSBucket( _get_db(self.model._mongometa.connection_alias)) self.storage = GridFSStorage(gridfs) try: raw_value = inst._data.get_python_value( self.attname, self.to_python) except KeyError: raw_value = self.default if self.is_blank(raw_value): return raw_value # Turn whatever value we have into a FieldFile instance. _file = self._to_field_file(raw_value, inst) # Store this transformed value back into the instance. inst._data.set_python_value(self.attname, _file) return self.to_python(_file) # Access from outside a Model instance. return self
def __get__(self, inst, owner): value = super(ReferenceField, self).__get__(inst, owner) MongoModelBase = _import('pymodm.base.models.MongoModelBase') if inst is not None and isinstance(inst, MongoModelBase): return self.to_python(value) return self
def __set__(self, inst, value): MongoModel = _import('pymodm.base.models.MongoModel') super(ReferenceField, self).__set__(inst, value) self._is_instance = isinstance(value, MongoModel)