diff --git a/mongoengine/base.py b/mongoengine/base.py index b4530c93..995f1326 100644 --- a/mongoengine/base.py +++ b/mongoengine/base.py @@ -616,6 +616,10 @@ class DocumentMetaclass(type): raise InvalidDocumentError("Reverse delete rules are not supported for EmbeddedDocuments (field: %s)" % field.name) f.document_type.register_delete_rule(new_class, field.name, delete_rule) + proxy_class = getattr(field, 'proxy_class', None) + if proxy_class is not None: + new_class.register_proxy_field(field.name, proxy_class) + if field.name and hasattr(Document, field.name) and EmbeddedDocument not in new_class.mro(): raise InvalidDocumentError("%s is a document method and not a valid field name" % field.name) @@ -717,6 +721,7 @@ class TopLevelDocumentMetaclass(DocumentMetaclass): 'index_opts': {}, 'queryset_class': QuerySet, 'delete_rules': {}, + 'proxy_fields': {}, 'allow_inheritance': True } diff --git a/mongoengine/document.py b/mongoengine/document.py index 1d89cfff..fb9c4bcc 100644 --- a/mongoengine/document.py +++ b/mongoengine/document.py @@ -277,6 +277,11 @@ class Document(BaseDocument): signals.pre_delete.send(self.__class__, document=self) try: + for field_name in self._meta['proxy_fields']: + proxy_class = self._meta['proxy_fields'][field_name] + if hasattr(proxy_class, 'delete'): + proxy = getattr(self, field_name) + proxy.delete() self.__class__.objects(pk=self.pk).delete(safe=safe) except pymongo.errors.OperationFailure, err: message = u'Could not delete document (%s)' % err.message @@ -341,6 +346,13 @@ class Document(BaseDocument): """ cls._meta['delete_rules'][(document_cls, field_name)] = rule + @classmethod + def register_proxy_field(cls, field_name, proxy_class): + """This method registers fields with proxy classes to delete them when + removing this object. + """ + cls._meta['proxy_fields'][field_name] = proxy_class + @classmethod def drop_collection(cls): """Drops the entire collection associated with this diff --git a/tests/fields.py b/tests/fields.py index 81328f8e..31d3b588 100644 --- a/tests/fields.py +++ b/tests/fields.py @@ -1546,6 +1546,39 @@ class FieldTest(unittest.TestCase): file = FileField() DemoFile.objects.create() + def test_file_delete_cleanup(self): + """Ensure that the gridfs file is deleted when a document + with a GridFSProxied Field is deleted""" + class TestFile(Document): + file = FileField() + + class TestImage(Document): + image = ImageField() + + TestFile.drop_collection() + + testfile = TestFile() + testfile.file.put('Hello, World!') + testfile.save() + + testfile_grid_id = testfile.file.grid_id + testfile_fs = testfile.file.fs + + testfile.delete() + self.assertFalse(testfile_fs.exists(testfile_grid_id)) + + TestImage.drop_collection() + + testimage = TestImage() + testimage.image.put(open(TEST_IMAGE_PATH, 'r')) + testimage.save() + + testimage_grid_id = testimage.image.grid_id + testimage_fs = testimage.image.fs + + testimage.delete() + self.assertFalse(testimage_fs.exists(testimage_grid_id)) + def test_file_uniqueness(self): """Ensure that each instance of a FileField is unique """