mirror of
https://github.com/Hopiu/django-model-utils.git
synced 2026-03-16 20:00:23 +00:00
Add available_objects soft deletable model manager. Emit deprecation warning when using objects soft deletable manager.
This commit is contained in:
parent
eb00f65c81
commit
b7a160936f
6 changed files with 44 additions and 16 deletions
|
|
@ -15,6 +15,7 @@
|
|||
| Bo Marchman <bo.marchman@gmail.com>
|
||||
| Bojan Mihelac <bmihelac@mihelac.org>
|
||||
| Bruno Alla <bruno.alla@founders4schools.org.uk>
|
||||
| Craig Anderson <craiga@craiga.id.au>
|
||||
| Daniel Andrlik <daniel@andrlik.org>
|
||||
| Daniel Stanton <stringsonfire@me.com>
|
||||
| Den Lesnov <den-lesnov@yandex-team.ru>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ CHANGES
|
|||
- `FieldTracker` now respects `update_fields` changed in overridden `save()`
|
||||
method
|
||||
- Replace ugettext_lazy with gettext_lazy to satisfy Django deprecation warning
|
||||
- Add available_objects manager to SoftDeletableModel and add deprecation
|
||||
warning to objects manager.
|
||||
|
||||
4.0.0 (2019-12-11)
|
||||
------------------
|
||||
|
|
|
|||
|
|
@ -83,9 +83,13 @@ returns objects with that status only:
|
|||
SoftDeletableModel
|
||||
------------------
|
||||
|
||||
This abstract base class just provides field ``is_removed`` which is
|
||||
This abstract base class just provides a field ``is_removed`` which is
|
||||
set to True instead of removing the instance. Entities returned in
|
||||
default manager are limited to not-deleted instances.
|
||||
manager ``available_objects`` are limited to not-deleted instances.
|
||||
|
||||
Note that relying on the default ``objects`` manager to filter out not-deleted
|
||||
instances is deprecated. ``objects`` will include deleted objects in a future
|
||||
release.
|
||||
|
||||
|
||||
UUIDModel
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import warnings
|
||||
|
||||
import django
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import connection
|
||||
|
|
@ -282,10 +284,25 @@ class SoftDeletableManagerMixin:
|
|||
"""
|
||||
_queryset_class = SoftDeletableQuerySet
|
||||
|
||||
def __init__(self, *args, _emit_deprecation_warnings=False, **kwargs):
|
||||
self.emit_deprecation_warnings = _emit_deprecation_warnings
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Return queryset limited to not removed entries.
|
||||
"""
|
||||
|
||||
if self.emit_deprecation_warnings:
|
||||
warning_message = (
|
||||
"{0}.objects model manager will include soft-deleted objects in an "
|
||||
"upcoming release; please use {0}.available_objects to continue "
|
||||
"excluding soft-deleted objects. See "
|
||||
"https://django-model-utils.readthedocs.io/en/stable/models.html"
|
||||
"#softdeletablemodel for more information."
|
||||
).format(self.model.__class__.__name__)
|
||||
warnings.warn(warning_message, DeprecationWarning)
|
||||
|
||||
kwargs = {'model': self.model, 'using': self._db}
|
||||
if hasattr(self, '_hints'):
|
||||
kwargs['hints'] = self._hints
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class TimeStampedModel(models.Model):
|
|||
if 'update_fields' in kwargs and 'modified' not in kwargs['update_fields']:
|
||||
kwargs['update_fields'] += ['modified']
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
|
@ -132,7 +132,8 @@ class SoftDeletableModel(models.Model):
|
|||
class Meta:
|
||||
abstract = True
|
||||
|
||||
objects = SoftDeletableManager()
|
||||
objects = SoftDeletableManager(_emit_deprecation_warnings=True)
|
||||
available_objects = SoftDeletableManager()
|
||||
all_objects = models.Manager()
|
||||
|
||||
def delete(self, using=None, soft=True, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -6,45 +6,48 @@ from tests.models import SoftDeletable
|
|||
|
||||
class SoftDeletableModelTests(TestCase):
|
||||
def test_can_only_see_not_removed_entries(self):
|
||||
SoftDeletable.objects.create(name='a', is_removed=True)
|
||||
SoftDeletable.objects.create(name='b', is_removed=False)
|
||||
SoftDeletable.available_objects.create(name='a', is_removed=True)
|
||||
SoftDeletable.available_objects.create(name='b', is_removed=False)
|
||||
|
||||
queryset = SoftDeletable.objects.all()
|
||||
queryset = SoftDeletable.available_objects.all()
|
||||
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertEqual(queryset[0].name, 'b')
|
||||
|
||||
def test_instance_cannot_be_fully_deleted(self):
|
||||
instance = SoftDeletable.objects.create(name='a')
|
||||
instance = SoftDeletable.available_objects.create(name='a')
|
||||
|
||||
instance.delete()
|
||||
|
||||
self.assertEqual(SoftDeletable.objects.count(), 0)
|
||||
self.assertEqual(SoftDeletable.available_objects.count(), 0)
|
||||
self.assertEqual(SoftDeletable.all_objects.count(), 1)
|
||||
|
||||
def test_instance_cannot_be_fully_deleted_via_queryset(self):
|
||||
SoftDeletable.objects.create(name='a')
|
||||
SoftDeletable.available_objects.create(name='a')
|
||||
|
||||
SoftDeletable.objects.all().delete()
|
||||
SoftDeletable.available_objects.all().delete()
|
||||
|
||||
self.assertEqual(SoftDeletable.objects.count(), 0)
|
||||
self.assertEqual(SoftDeletable.available_objects.count(), 0)
|
||||
self.assertEqual(SoftDeletable.all_objects.count(), 1)
|
||||
|
||||
def test_delete_instance_no_connection(self):
|
||||
obj = SoftDeletable.objects.create(name='a')
|
||||
obj = SoftDeletable.available_objects.create(name='a')
|
||||
|
||||
self.assertRaises(ConnectionDoesNotExist, obj.delete, using='other')
|
||||
|
||||
def test_instance_purge(self):
|
||||
instance = SoftDeletable.objects.create(name='a')
|
||||
instance = SoftDeletable.available_objects.create(name='a')
|
||||
|
||||
instance.delete(soft=False)
|
||||
|
||||
self.assertEqual(SoftDeletable.objects.count(), 0)
|
||||
self.assertEqual(SoftDeletable.available_objects.count(), 0)
|
||||
self.assertEqual(SoftDeletable.all_objects.count(), 0)
|
||||
|
||||
def test_instance_purge_no_connection(self):
|
||||
instance = SoftDeletable.objects.create(name='a')
|
||||
instance = SoftDeletable.available_objects.create(name='a')
|
||||
|
||||
self.assertRaises(ConnectionDoesNotExist, instance.delete,
|
||||
using='other', soft=False)
|
||||
|
||||
def test_deprecation_warning(self):
|
||||
self.assertWarns(DeprecationWarning, SoftDeletable.objects.all)
|
||||
|
|
|
|||
Loading…
Reference in a new issue