diff --git a/CHANGES.rst b/CHANGES.rst index f10c32ab..f05354ba 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,6 +16,7 @@ To be released - Make `soft` argument to `SoftDeletableModel.delete()` keyword-only - `JoinManager` and `JoinManagerMixin` have been deprecated; please use ``JoinQueryset.as_manager()`` instead +- Change `SoftDeletableQuerySetMixin.delete` to replicate Django's API. 4.5.1 (2024-05-02) ------------------ diff --git a/model_utils/managers.py b/model_utils/managers.py index 899b9887..4cb1ffcd 100644 --- a/model_utils/managers.py +++ b/model_utils/managers.py @@ -363,17 +363,17 @@ class SoftDeletableQuerySetMixin(Generic[ModelT]): its ``is_removed`` field to True. """ - def delete(self) -> None: + def delete(self) -> tuple[int, dict[str, int]]: """ Soft delete objects from queryset (set their ``is_removed`` field to True) """ - cast(QuerySet[ModelT], self).update(is_removed=True) + model: type[ModelT] = self.model # type: ignore[attr-defined] + number_of_deleted_objects = cast(QuerySet[ModelT], self).update(is_removed=True) + return number_of_deleted_objects, {model._meta.label: number_of_deleted_objects} -# Note that our delete() method does not return anything, unlike Django's. -# https://github.com/jazzband/django-model-utils/issues/541 -class SoftDeletableQuerySet(SoftDeletableQuerySetMixin[ModelT], QuerySet[ModelT]): # type: ignore[misc] +class SoftDeletableQuerySet(SoftDeletableQuerySetMixin[ModelT], QuerySet[ModelT]): pass diff --git a/tests/test_models/test_softdeletable_model.py b/tests/test_models/test_softdeletable_model.py index 1f58f435..8f4e656c 100644 --- a/tests/test_models/test_softdeletable_model.py +++ b/tests/test_models/test_softdeletable_model.py @@ -53,3 +53,13 @@ def test_instance_purge_no_connection(self) -> None: def test_deprecation_warning(self) -> None: self.assertWarns(DeprecationWarning, SoftDeletable.objects.all) + + def test_delete_queryset_return(self) -> None: + SoftDeletable.available_objects.create(name='a') + SoftDeletable.available_objects.create(name='b') + + result = SoftDeletable.available_objects.filter(name="a").delete() + + assert result == ( + 1, {SoftDeletable._meta.label: 1} + )