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:
Vincent Driessen 2010-12-13 12:36:24 -08:00
parent 3c98a4bff5
commit 07dae64d66
4 changed files with 65 additions and 22 deletions

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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.