From b2dc8d36a24c84c8c475454d3d05bd05bc19207e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Fantone?= Date: Fri, 6 Sep 2024 13:34:17 +0100 Subject: [PATCH] Add proper return value to MockSet delete --- django_mock_queries/query.py | 25 +++++++++++++++++++++---- tests/test_query.py | 8 ++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/django_mock_queries/query.py b/django_mock_queries/query.py index 2cf78c9..4b4e40a 100644 --- a/django_mock_queries/query.py +++ b/django_mock_queries/query.py @@ -1,6 +1,6 @@ import datetime import random -from collections import OrderedDict, namedtuple +from collections import OrderedDict, defaultdict, namedtuple from unittest.mock import Mock, MagicMock, PropertyMock from .constants import * @@ -267,16 +267,22 @@ def update(self, **attrs): return count def _delete_recursive(self, *items_to_remove, **attrs): + removed_items = defaultdict(int) + for item in matches(*items_to_remove, **attrs): self.items.remove(item) self.fire(item, self.EVENT_DELETED) + item_label = item._meta.label if hasattr(item, '_meta') else type(item).__name__ + removed_items[item_label] += 1 if self.clone is not None: self.clone._delete_recursive(*items_to_remove, **attrs) + return sum(removed_items.values()), removed_items + def delete(self, **attrs): # Delete normally doesn't take **attrs - they're only needed for remove - self._delete_recursive(*self.items, **attrs) + return self._delete_recursive(*self.items, **attrs) # The following 2 methods were kept for backwards compatibility and # should be removed in the future since they are covered by filter & delete @@ -437,7 +443,8 @@ def __init__(self, *args, **kwargs): super(MockModel, self).__init__(*args, **kwargs) self.save = PropertyMock() - self.__meta = MockOptions(*self.get_fields()) + object_name = self.get('mock_name', type(self).__name__) + self.__meta = MockOptions(object_name, *self.get_fields()) def __getattr__(self, item): return self.get(item, None) @@ -471,9 +478,19 @@ def create_model(*fields): class MockOptions: - def __init__(self, *field_names): + def __init__(self, object_name, *field_names): self.load_fields(*field_names) self.get_latest_by = None + self.object_name = object_name + self.model_name = object_name.lower() + + @property + def label(self): + return self.object_name + + @property + def label_lower(self): + return self.model_name def load_fields(self, *field_names): fields = {name: MockField(name) for name in field_names} diff --git a/tests/test_query.py b/tests/test_query.py index 66ad52a..9c8d00e 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -706,20 +706,24 @@ def test_query_delete_all_entries(self): item_2 = MockModel(foo=1, bar='b', mock_name='item_2') self.mock_set.add(item_1, item_2) - self.mock_set.delete() + deleted_count, deleted_items = self.mock_set.delete() assert len(self.mock_set) == 0, len(self.mock_set) + assert deleted_count == 2 + assert deleted_items == {'item_1': 1, 'item_2': 1} def test_query_delete_entries_propagated_from_nested_qs(self): item_1 = MockModel(foo=1, bar='a', mock_name='item_1') item_2 = MockModel(foo=1, bar='b', mock_name='item_2') self.mock_set.add(item_1, item_2) - self.mock_set.filter(bar='b').delete() + deleted_count, deleted_items = self.mock_set.filter(bar='b').delete() assert len(self.mock_set) == 1, len(self.mock_set) assert item_1 in self.mock_set assert item_2 not in self.mock_set + assert deleted_count == 1 + assert deleted_items == {'item_2': 1} def test_query_gets_unique_match_by_attrs_from_set(self): item_1 = MockModel(foo=1)