Merge pull request #825 from idlead/fix/reverse_delete_rules_on_abstract_documents

Fix crash when applying deletion rules
This commit is contained in:
Wilson Júnior 2014-12-04 09:23:59 -02:00
commit d889cc3c5a
2 changed files with 108 additions and 0 deletions

View File

@ -432,6 +432,8 @@ class BaseQuerySet(object):
# references # references
for rule_entry in delete_rules: for rule_entry in delete_rules:
document_cls, field_name = rule_entry document_cls, field_name = rule_entry
if document_cls._meta.get('abstract'):
continue
rule = doc._meta['delete_rules'][rule_entry] rule = doc._meta['delete_rules'][rule_entry]
if rule == DENY and document_cls.objects( if rule == DENY and document_cls.objects(
**{field_name + '__in': self}).count() > 0: **{field_name + '__in': self}).count() > 0:
@ -441,6 +443,8 @@ class BaseQuerySet(object):
for rule_entry in delete_rules: for rule_entry in delete_rules:
document_cls, field_name = rule_entry document_cls, field_name = rule_entry
if document_cls._meta.get('abstract'):
continue
rule = doc._meta['delete_rules'][rule_entry] rule = doc._meta['delete_rules'][rule_entry]
if rule == CASCADE: if rule == CASCADE:
ref_q = document_cls.objects(**{field_name + '__in': self}) ref_q = document_cls.objects(**{field_name + '__in': self})

View File

@ -1302,6 +1302,31 @@ class QuerySetTest(unittest.TestCase):
self.Person.objects(name='Test User').delete() self.Person.objects(name='Test User').delete()
self.assertEqual(1, BlogPost.objects.count()) self.assertEqual(1, BlogPost.objects.count())
def test_reverse_delete_rule_cascade_on_abstract_document(self):
"""Ensure cascading deletion of referring documents from the database
does not fail on abstract document.
"""
class AbstractBlogPost(Document):
meta = {'abstract': True}
author = ReferenceField(self.Person, reverse_delete_rule=CASCADE)
class BlogPost(AbstractBlogPost):
content = StringField()
BlogPost.drop_collection()
me = self.Person(name='Test User')
me.save()
someoneelse = self.Person(name='Some-one Else')
someoneelse.save()
BlogPost(content='Watching TV', author=me).save()
BlogPost(content='Chilling out', author=me).save()
BlogPost(content='Pro Testing', author=someoneelse).save()
self.assertEqual(3, BlogPost.objects.count())
self.Person.objects(name='Test User').delete()
self.assertEqual(1, BlogPost.objects.count())
def test_reverse_delete_rule_cascade_self_referencing(self): def test_reverse_delete_rule_cascade_self_referencing(self):
"""Ensure self-referencing CASCADE deletes do not result in infinite """Ensure self-referencing CASCADE deletes do not result in infinite
loop loop
@ -1361,6 +1386,31 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(1, BlogPost.objects.count()) self.assertEqual(1, BlogPost.objects.count())
self.assertEqual(None, BlogPost.objects.first().category) self.assertEqual(None, BlogPost.objects.first().category)
def test_reverse_delete_rule_nullify_on_abstract_document(self):
"""Ensure nullification of references to deleted documents when
reference is on an abstract document.
"""
class AbstractBlogPost(Document):
meta = {'abstract': True}
author = ReferenceField(self.Person, reverse_delete_rule=NULLIFY)
class BlogPost(AbstractBlogPost):
content = StringField()
BlogPost.drop_collection()
me = self.Person(name='Test User')
me.save()
someoneelse = self.Person(name='Some-one Else')
someoneelse.save()
BlogPost(content='Watching TV', author=me).save()
self.assertEqual(1, BlogPost.objects.count())
self.assertEqual(me, BlogPost.objects.first().author)
self.Person.objects(name='Test User').delete()
self.assertEqual(1, BlogPost.objects.count())
self.assertEqual(None, BlogPost.objects.first().author)
def test_reverse_delete_rule_deny(self): def test_reverse_delete_rule_deny(self):
"""Ensure deletion gets denied on documents that still have references """Ensure deletion gets denied on documents that still have references
to them. to them.
@ -1380,6 +1430,26 @@ class QuerySetTest(unittest.TestCase):
self.assertRaises(OperationError, self.Person.objects.delete) self.assertRaises(OperationError, self.Person.objects.delete)
def test_reverse_delete_rule_deny_on_abstract_document(self):
"""Ensure deletion gets denied on documents that still have references
to them, when reference is on an abstract document.
"""
class AbstractBlogPost(Document):
meta = {'abstract': True}
author = ReferenceField(self.Person, reverse_delete_rule=DENY)
class BlogPost(AbstractBlogPost):
content = StringField()
BlogPost.drop_collection()
me = self.Person(name='Test User')
me.save()
BlogPost(content='Watching TV', author=me).save()
self.assertEqual(1, BlogPost.objects.count())
self.assertRaises(OperationError, self.Person.objects.delete)
def test_reverse_delete_rule_pull(self): def test_reverse_delete_rule_pull(self):
"""Ensure pulling of references to deleted documents. """Ensure pulling of references to deleted documents.
""" """
@ -1410,6 +1480,40 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(post.authors, [me]) self.assertEqual(post.authors, [me])
self.assertEqual(another.authors, []) self.assertEqual(another.authors, [])
def test_reverse_delete_rule_pull_on_abstract_documents(self):
"""Ensure pulling of references to deleted documents when reference
is defined on an abstract document..
"""
class AbstractBlogPost(Document):
meta = {'abstract': True}
authors = ListField(ReferenceField(self.Person,
reverse_delete_rule=PULL))
class BlogPost(AbstractBlogPost):
content = StringField()
BlogPost.drop_collection()
self.Person.drop_collection()
me = self.Person(name='Test User')
me.save()
someoneelse = self.Person(name='Some-one Else')
someoneelse.save()
post = BlogPost(content='Watching TV', authors=[me, someoneelse])
post.save()
another = BlogPost(content='Chilling Out', authors=[someoneelse])
another.save()
someoneelse.delete()
post.reload()
another.reload()
self.assertEqual(post.authors, [me])
self.assertEqual(another.authors, [])
def test_delete_with_limits(self): def test_delete_with_limits(self):
class Log(Document): class Log(Document):