Added Reverse Delete Rule support to ListFields
DictFields and MapFields aren't supported and raise an InvalidDocument Error Closes #254
This commit is contained in:
		| @@ -503,15 +503,22 @@ class DocumentMetaclass(type): | |||||||
|         attrs['_db_field_map'] = dict([(k, v.db_field) for k, v in doc_fields.items() if k!=v.db_field]) |         attrs['_db_field_map'] = dict([(k, v.db_field) for k, v in doc_fields.items() if k!=v.db_field]) | ||||||
|         attrs['_reverse_db_field_map'] = dict([(v, k) for k, v in attrs['_db_field_map'].items()]) |         attrs['_reverse_db_field_map'] = dict([(v, k) for k, v in attrs['_db_field_map'].items()]) | ||||||
|  |  | ||||||
|         from mongoengine import Document, EmbeddedDocument |         from mongoengine import Document, EmbeddedDocument, DictField | ||||||
|  |  | ||||||
|         new_class = super_new(cls, name, bases, attrs) |         new_class = super_new(cls, name, bases, attrs) | ||||||
|         for field in new_class._fields.values(): |         for field in new_class._fields.values(): | ||||||
|             field.owner_document = new_class |             field.owner_document = new_class | ||||||
|  |  | ||||||
|             delete_rule = getattr(field, 'reverse_delete_rule', DO_NOTHING) |             delete_rule = getattr(field, 'reverse_delete_rule', DO_NOTHING) | ||||||
|  |             f = field | ||||||
|  |             if isinstance(f, ComplexBaseField) and hasattr(f, 'field'): | ||||||
|  |                 delete_rule = getattr(f.field, 'reverse_delete_rule', DO_NOTHING) | ||||||
|  |                 if isinstance(f, DictField) and delete_rule != DO_NOTHING: | ||||||
|  |                     raise InvalidDocumentError("Reverse delete rules are not supported for %s (field: %s)" % (field.__class__.__name__, field.name)) | ||||||
|  |                 f = field.field | ||||||
|  |  | ||||||
|             if delete_rule != DO_NOTHING: |             if delete_rule != DO_NOTHING: | ||||||
|                 field.document_type.register_delete_rule(new_class, field.name, |                 f.document_type.register_delete_rule(new_class, field.name, delete_rule) | ||||||
|                         delete_rule) |  | ||||||
|  |  | ||||||
|             if field.name and hasattr(Document, field.name) and EmbeddedDocument not in new_class.mro(): |             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) |                 raise InvalidDocumentError("%s is a document method and not a valid field name" % field.name) | ||||||
|   | |||||||
| @@ -2214,6 +2214,46 @@ class DocumentTest(unittest.TestCase): | |||||||
|         author.delete() |         author.delete() | ||||||
|         self.assertEqual(len(BlogPost.objects), 0) |         self.assertEqual(len(BlogPost.objects), 0) | ||||||
|  |  | ||||||
|  |     def test_reverse_delete_rule_cascade_and_nullify_complex_field(self): | ||||||
|  |         """Ensure that a referenced document is also deleted upon deletion. | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         class BlogPost(Document): | ||||||
|  |             content = StringField() | ||||||
|  |             authors = ListField(ReferenceField(self.Person, reverse_delete_rule=CASCADE)) | ||||||
|  |             reviewers = ListField(ReferenceField(self.Person, reverse_delete_rule=NULLIFY)) | ||||||
|  |  | ||||||
|  |         self.Person.drop_collection() | ||||||
|  |         BlogPost.drop_collection() | ||||||
|  |  | ||||||
|  |         author = self.Person(name='Test User') | ||||||
|  |         author.save() | ||||||
|  |  | ||||||
|  |         reviewer = self.Person(name='Re Viewer') | ||||||
|  |         reviewer.save() | ||||||
|  |  | ||||||
|  |         post = BlogPost(content= 'Watched some TV') | ||||||
|  |         post.authors = [author] | ||||||
|  |         post.reviewers = [reviewer] | ||||||
|  |         post.save() | ||||||
|  |  | ||||||
|  |         reviewer.delete() | ||||||
|  |         self.assertEqual(len(BlogPost.objects), 1)  # No effect on the BlogPost | ||||||
|  |         self.assertEqual(BlogPost.objects.get().reviewers, []) | ||||||
|  |  | ||||||
|  |         # Delete the Person, which should lead to deletion of the BlogPost, too | ||||||
|  |         author.delete() | ||||||
|  |         self.assertEqual(len(BlogPost.objects), 0) | ||||||
|  |  | ||||||
|  |         def throw_invalid_document_error(): | ||||||
|  |             class Blog(Document): | ||||||
|  |                 content = StringField() | ||||||
|  |                 authors = MapField(ReferenceField(self.Person, reverse_delete_rule=CASCADE)) | ||||||
|  |                 reviewers = DictField(field=ReferenceField(self.Person, reverse_delete_rule=NULLIFY)) | ||||||
|  |  | ||||||
|  |         self.assertRaises(InvalidDocumentError, throw_invalid_document_error) | ||||||
|  |  | ||||||
|  |  | ||||||
|     def test_reverse_delete_rule_cascade_recurs(self): |     def test_reverse_delete_rule_cascade_recurs(self): | ||||||
|         """Ensure that a chain of documents is also deleted upon cascaded |         """Ensure that a chain of documents is also deleted upon cascaded | ||||||
|         deletion. |         deletion. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user