Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions mongoengine/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,10 @@ def _get_mixin_fields(base):
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)

Expand Down Expand Up @@ -717,6 +721,7 @@ def __new__(cls, name, bases, attrs):
'index_opts': {},
'queryset_class': QuerySet,
'delete_rules': {},
'proxy_fields': {},
'allow_inheritance': True
}

Expand Down
12 changes: 12 additions & 0 deletions mongoengine/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,11 @@ def delete(self, safe=False):
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
Expand Down Expand Up @@ -341,6 +346,13 @@ def register_delete_rule(cls, document_cls, field_name, rule):
"""
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
Expand Down
33 changes: 33 additions & 0 deletions tests/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,39 @@ class DemoFile(Document):
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
"""
Expand Down