More the deletion code over to the QuerySet object.
The Document object doens't have any delete_rule specific code anymore, and leverages the QuerySet's ability to deny/cascade/nullify its relations.
This commit is contained in:
parent
3c98a4bff5
commit
07dae64d66
@ -99,26 +99,6 @@ class Document(BaseDocument):
|
|||||||
|
|
||||||
:param safe: check if the operation succeeded before returning
|
:param safe: check if the operation succeeded before returning
|
||||||
"""
|
"""
|
||||||
# Check for DENY rules before actually deleting/nullifying any other
|
|
||||||
# references
|
|
||||||
for rule_entry in self._meta['delete_rules']:
|
|
||||||
document_cls, field_name = rule_entry
|
|
||||||
rule = self._meta['delete_rules'][rule_entry]
|
|
||||||
if rule == DENY and document_cls.objects(**{field_name: self.id}).count() > 0:
|
|
||||||
msg = u'Could not delete document (at least %s.%s refers to it)' % \
|
|
||||||
(document_cls.__name__, field_name)
|
|
||||||
raise OperationError(msg)
|
|
||||||
|
|
||||||
for rule_entry in self._meta['delete_rules']:
|
|
||||||
document_cls, field_name = rule_entry
|
|
||||||
rule = self._meta['delete_rules'][rule_entry]
|
|
||||||
|
|
||||||
if rule == CASCADE:
|
|
||||||
document_cls.objects(**{field_name: self.id}).delete(safe=safe)
|
|
||||||
elif rule == NULLIFY:
|
|
||||||
document_cls.objects(**{field_name:
|
|
||||||
self.id}).update(**{'unset__%s' % field_name: 1})
|
|
||||||
|
|
||||||
id_field = self._meta['id_field']
|
id_field = self._meta['id_field']
|
||||||
object_id = self._fields[id_field].to_mongo(self[id_field])
|
object_id = self._fields[id_field].to_mongo(self[id_field])
|
||||||
try:
|
try:
|
||||||
|
@ -882,6 +882,28 @@ class QuerySet(object):
|
|||||||
|
|
||||||
:param safe: check if the operation succeeded before returning
|
:param safe: check if the operation succeeded before returning
|
||||||
"""
|
"""
|
||||||
|
from document import CASCADE, DENY, NULLIFY
|
||||||
|
|
||||||
|
doc = self._document
|
||||||
|
|
||||||
|
# Check for DENY rules before actually deleting/nullifying any other
|
||||||
|
# references
|
||||||
|
for rule_entry in doc._meta['delete_rules']:
|
||||||
|
document_cls, field_name = rule_entry
|
||||||
|
rule = doc._meta['delete_rules'][rule_entry]
|
||||||
|
if rule == DENY and document_cls.objects(**{field_name + '__in': self}).count() > 0:
|
||||||
|
msg = u'Could not delete document (at least %s.%s refers to it)' % \
|
||||||
|
(document_cls.__name__, field_name)
|
||||||
|
raise OperationError(msg)
|
||||||
|
|
||||||
|
for rule_entry in doc._meta['delete_rules']:
|
||||||
|
document_cls, field_name = rule_entry
|
||||||
|
rule = doc._meta['delete_rules'][rule_entry]
|
||||||
|
if rule == CASCADE:
|
||||||
|
document_cls.objects(**{field_name + '__in': self}).delete(safe=safe)
|
||||||
|
elif rule == NULLIFY:
|
||||||
|
document_cls.objects(**{field_name + '__in': self}).update(**{'unset__%s' % field_name: 1})
|
||||||
|
|
||||||
self._collection.remove(self._query, safe=safe)
|
self._collection.remove(self._query, safe=safe)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -661,7 +661,35 @@ class DocumentTest(unittest.TestCase):
|
|||||||
"""Ensure that a chain of documents is also deleted upon cascaded
|
"""Ensure that a chain of documents is also deleted upon cascaded
|
||||||
deletion.
|
deletion.
|
||||||
"""
|
"""
|
||||||
self.fail()
|
|
||||||
|
class BlogPost(Document):
|
||||||
|
content = StringField()
|
||||||
|
author = ReferenceField(self.Person, delete_rule=CASCADE)
|
||||||
|
|
||||||
|
class Comment(Document):
|
||||||
|
text = StringField()
|
||||||
|
post = ReferenceField(BlogPost, delete_rule=CASCADE)
|
||||||
|
|
||||||
|
|
||||||
|
author = self.Person(name='Test User')
|
||||||
|
author.save()
|
||||||
|
|
||||||
|
post = BlogPost(content = 'Watched some TV')
|
||||||
|
post.author = author
|
||||||
|
post.save()
|
||||||
|
|
||||||
|
comment = Comment(text = 'Kudos.')
|
||||||
|
comment.post = post
|
||||||
|
comment.save()
|
||||||
|
|
||||||
|
# Delete the Person, which should lead to deletion of the BlogPost, and,
|
||||||
|
# recursively to the Comment, too
|
||||||
|
author.delete()
|
||||||
|
self.assertEqual(len(Comment.objects), 0)
|
||||||
|
|
||||||
|
self.Person.drop_collection()
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
Comment.drop_collection()
|
||||||
|
|
||||||
def test_delete_rule_deny(self):
|
def test_delete_rule_deny(self):
|
||||||
"""Ensure that a document cannot be referenced if there are still
|
"""Ensure that a document cannot be referenced if there are still
|
||||||
|
@ -737,7 +737,20 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
def test_delete_rule_cascade(self):
|
def test_delete_rule_cascade(self):
|
||||||
"""Ensure cascading deletion of referring documents from the database.
|
"""Ensure cascading deletion of referring documents from the database.
|
||||||
"""
|
"""
|
||||||
self.fail()
|
class BlogPost(Document):
|
||||||
|
content = StringField()
|
||||||
|
author = ReferenceField(self.Person, delete_rule=CASCADE)
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
|
me = self.Person(name='Test User')
|
||||||
|
me.save()
|
||||||
|
|
||||||
|
post = BlogPost(content='Watching TV', author=me)
|
||||||
|
post.save()
|
||||||
|
|
||||||
|
self.assertEqual(1, BlogPost.objects.count())
|
||||||
|
self.Person.objects.delete()
|
||||||
|
self.assertEqual(0, BlogPost.objects.count())
|
||||||
|
|
||||||
def test_delete_rule_nullify(self):
|
def test_delete_rule_nullify(self):
|
||||||
"""Ensure nullification of references to deleted documents.
|
"""Ensure nullification of references to deleted documents.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user