Fix cascade delete mixing among collections
This commit is contained in:
		| @@ -5,6 +5,7 @@ Changelog | |||||||
| Changes in 0.10.7 - DEV | Changes in 0.10.7 - DEV | ||||||
| ======================= | ======================= | ||||||
| - Fixed not being able to specify `use_db_field=False` on `ListField(EmbeddedDocumentField)` instances | - Fixed not being able to specify `use_db_field=False` on `ListField(EmbeddedDocumentField)` instances | ||||||
|  | - Fixed cascade delete mixing among collections #1224 | ||||||
|  |  | ||||||
| Changes in 0.10.6 | Changes in 0.10.6 | ||||||
| ================= | ================= | ||||||
|   | |||||||
| @@ -403,8 +403,10 @@ class BaseQuerySet(object): | |||||||
|             rule = doc._meta['delete_rules'][rule_entry] |             rule = doc._meta['delete_rules'][rule_entry] | ||||||
|             if rule == CASCADE: |             if rule == CASCADE: | ||||||
|                 cascade_refs = set() if cascade_refs is None else cascade_refs |                 cascade_refs = set() if cascade_refs is None else cascade_refs | ||||||
|                 for ref in queryset: |                 # Handle recursive reference | ||||||
|                     cascade_refs.add(ref.id) |                 if doc._collection == document_cls._collection: | ||||||
|  |                     for ref in queryset: | ||||||
|  |                         cascade_refs.add(ref.id) | ||||||
|                 ref_q = document_cls.objects(**{field_name + '__in': self, 'id__nin': cascade_refs}) |                 ref_q = document_cls.objects(**{field_name + '__in': self, 'id__nin': cascade_refs}) | ||||||
|                 ref_q_count = ref_q.count() |                 ref_q_count = ref_q.count() | ||||||
|                 if ref_q_count > 0: |                 if ref_q_count > 0: | ||||||
|   | |||||||
| @@ -1906,6 +1906,62 @@ class InstanceTest(unittest.TestCase): | |||||||
|         author.delete() |         author.delete() | ||||||
|         self.assertEqual(BlogPost.objects.count(), 0) |         self.assertEqual(BlogPost.objects.count(), 0) | ||||||
|  |  | ||||||
|  |     def test_reverse_delete_rule_with_custom_id_field(self): | ||||||
|  |         """Ensure that a referenced document with custom primary key | ||||||
|  |         is also deleted upon deletion. | ||||||
|  |         """ | ||||||
|  |         class User(Document): | ||||||
|  |             name = StringField(primary_key=True) | ||||||
|  |  | ||||||
|  |         class Book(Document): | ||||||
|  |             author = ReferenceField(User, reverse_delete_rule=CASCADE) | ||||||
|  |             reviewer = ReferenceField(User, reverse_delete_rule=NULLIFY) | ||||||
|  |  | ||||||
|  |         User.drop_collection() | ||||||
|  |         Book.drop_collection() | ||||||
|  |  | ||||||
|  |         user = User(name='Mike').save() | ||||||
|  |         reviewer = User(name='John').save() | ||||||
|  |         book = Book(author=user, reviewer=reviewer).save() | ||||||
|  |  | ||||||
|  |         reviewer.delete() | ||||||
|  |         self.assertEqual(Book.objects.count(), 1) | ||||||
|  |         self.assertEqual(Book.objects.get().reviewer, None) | ||||||
|  |  | ||||||
|  |         user.delete() | ||||||
|  |         self.assertEqual(Book.objects.count(), 0) | ||||||
|  |  | ||||||
|  |     def test_reverse_delete_rule_with_shared_id_among_collections(self): | ||||||
|  |         """Ensure that cascade delete rule doesn't mix id among collections. | ||||||
|  |         """ | ||||||
|  |         class User(Document): | ||||||
|  |             id = IntField(primary_key=True) | ||||||
|  |  | ||||||
|  |         class Book(Document): | ||||||
|  |             id = IntField(primary_key=True) | ||||||
|  |             author = ReferenceField(User, reverse_delete_rule=CASCADE) | ||||||
|  |  | ||||||
|  |         User.drop_collection() | ||||||
|  |         Book.drop_collection() | ||||||
|  |  | ||||||
|  |         user_1 = User(id=1).save() | ||||||
|  |         user_2 = User(id=2).save() | ||||||
|  |         book_1 = Book(id=1, author=user_2).save() | ||||||
|  |         book_2 = Book(id=2, author=user_1).save() | ||||||
|  |  | ||||||
|  |         user_2.delete() | ||||||
|  |         # Deleting user_2 should also delete book_1 but not book_2 | ||||||
|  |         self.assertEqual(Book.objects.count(), 1) | ||||||
|  |         self.assertEqual(Book.objects.get(), book_2) | ||||||
|  |  | ||||||
|  |         user_3 = User(id=3).save() | ||||||
|  |         book_3 = Book(id=3, author=user_3).save() | ||||||
|  |  | ||||||
|  |         user_3.delete() | ||||||
|  |         # Deleting user_3 should also delete book_3 | ||||||
|  |         self.assertEqual(Book.objects.count(), 1) | ||||||
|  |         self.assertEqual(Book.objects.get(), book_2) | ||||||
|  |  | ||||||
|     def test_reverse_delete_rule_with_document_inheritance(self): |     def test_reverse_delete_rule_with_document_inheritance(self): | ||||||
|         """Ensure that a referenced document is also deleted upon deletion |         """Ensure that a referenced document is also deleted upon deletion | ||||||
|         of a child document. |         of a child document. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user