2016-11-23 23:49:53 +00:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
2016-03-27 00:02:49 +00:00
|
|
|
from unittest import skipUnless
|
|
|
|
|
|
2016-11-23 23:49:53 +00:00
|
|
|
import django
|
|
|
|
|
from django.core.exceptions import FieldError
|
|
|
|
|
from django.test import TestCase
|
|
|
|
|
|
|
|
|
|
from model_utils import FieldTracker
|
2018-06-29 00:04:57 +00:00
|
|
|
from model_utils.tracker import DescriptorWrapper
|
2017-02-15 23:00:10 +00:00
|
|
|
from tests.models import (
|
2016-11-23 23:49:53 +00:00
|
|
|
Tracked, TrackedFK, InheritedTrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple,
|
2016-11-24 21:31:23 +00:00
|
|
|
InheritedTracked, TrackedFileField,
|
|
|
|
|
ModelTracked, ModelTrackedFK, ModelTrackedNotDefault, ModelTrackedMultiple, InheritedModelTracked,
|
|
|
|
|
)
|
2016-11-23 23:49:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackerTestCase(TestCase):
|
|
|
|
|
|
|
|
|
|
tracker = None
|
|
|
|
|
|
|
|
|
|
def assertHasChanged(self, **kwargs):
|
|
|
|
|
tracker = kwargs.pop('tracker', self.tracker)
|
|
|
|
|
for field, value in kwargs.items():
|
|
|
|
|
if value is None:
|
|
|
|
|
with self.assertRaises(FieldError):
|
|
|
|
|
tracker.has_changed(field)
|
|
|
|
|
else:
|
|
|
|
|
self.assertEqual(tracker.has_changed(field), value)
|
|
|
|
|
|
|
|
|
|
def assertPrevious(self, **kwargs):
|
|
|
|
|
tracker = kwargs.pop('tracker', self.tracker)
|
|
|
|
|
for field, value in kwargs.items():
|
|
|
|
|
self.assertEqual(tracker.previous(field), value)
|
|
|
|
|
|
|
|
|
|
def assertChanged(self, **kwargs):
|
|
|
|
|
tracker = kwargs.pop('tracker', self.tracker)
|
|
|
|
|
self.assertEqual(tracker.changed(), kwargs)
|
|
|
|
|
|
|
|
|
|
def assertCurrent(self, **kwargs):
|
|
|
|
|
tracker = kwargs.pop('tracker', self.tracker)
|
|
|
|
|
self.assertEqual(tracker.current(), kwargs)
|
|
|
|
|
|
|
|
|
|
def update_instance(self, **kwargs):
|
|
|
|
|
for field, value in kwargs.items():
|
|
|
|
|
setattr(self.instance, field, value)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackerCommonTests(object):
|
|
|
|
|
|
|
|
|
|
def test_pre_save_previous(self):
|
|
|
|
|
self.assertPrevious(name=None, number=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertPrevious(name=None, number=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = Tracked
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.instance = self.tracked_class()
|
|
|
|
|
self.tracker = self.instance.tracker
|
|
|
|
|
|
|
|
|
|
def test_descriptor(self):
|
|
|
|
|
self.assertTrue(isinstance(self.tracked_class.tracker, FieldTracker))
|
|
|
|
|
|
|
|
|
|
def test_pre_save_changed(self):
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged(name=None, number=None)
|
|
|
|
|
self.instance.name = ''
|
|
|
|
|
self.assertChanged(name=None, number=None)
|
|
|
|
|
self.instance.mutable = [1,2,3]
|
|
|
|
|
self.assertChanged(name=None, number=None, mutable=None)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_has_changed(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=False, mutable=False)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=False, mutable=False)
|
|
|
|
|
self.instance.number = 7
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.mutable = [1,2,3]
|
|
|
|
|
self.assertHasChanged(name=True, number=True, mutable=True)
|
|
|
|
|
|
|
|
|
|
def test_first_save(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=False, mutable=False)
|
|
|
|
|
self.assertPrevious(name=None, number=None, mutable=None)
|
|
|
|
|
self.assertCurrent(name='', number=None, id=None, mutable=None)
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.instance.number = 4
|
|
|
|
|
self.instance.mutable = [1,2,3]
|
|
|
|
|
self.assertHasChanged(name=True, number=True, mutable=True)
|
|
|
|
|
self.assertPrevious(name=None, number=None, mutable=None)
|
|
|
|
|
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
|
|
|
|
|
self.assertChanged(name=None, number=None, mutable=None)
|
2016-03-27 00:02:49 +00:00
|
|
|
|
|
|
|
|
self.instance.save(update_fields=[])
|
|
|
|
|
self.assertHasChanged(name=True, number=True, mutable=True)
|
|
|
|
|
self.assertPrevious(name=None, number=None, mutable=None)
|
|
|
|
|
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
|
|
|
|
|
self.assertChanged(name=None, number=None, mutable=None)
|
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
|
self.instance.save(update_fields=['number'])
|
2016-11-23 23:49:53 +00:00
|
|
|
|
|
|
|
|
def test_post_save_has_changed(self):
|
|
|
|
|
self.update_instance(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
self.assertHasChanged(name=False, number=False, mutable=False)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=False)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.mutable[1] = 4
|
|
|
|
|
self.assertHasChanged(name=True, number=True, mutable=True)
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.assertHasChanged(name=False, number=True, mutable=True)
|
|
|
|
|
|
|
|
|
|
def test_post_save_previous(self):
|
|
|
|
|
self.update_instance(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertPrevious(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
self.instance.mutable[1] = 4
|
|
|
|
|
self.assertPrevious(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
|
|
|
|
|
def test_post_save_changed(self):
|
|
|
|
|
self.update_instance(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged(name='retro')
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged(name='retro', number=4)
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.assertChanged(number=4)
|
|
|
|
|
self.instance.mutable[1] = 4
|
|
|
|
|
self.assertChanged(number=4, mutable=[1,2,3])
|
|
|
|
|
self.instance.mutable = [1,2,3]
|
|
|
|
|
self.assertChanged(number=4)
|
|
|
|
|
|
|
|
|
|
def test_current(self):
|
|
|
|
|
self.assertCurrent(id=None, name='', number=None, mutable=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertCurrent(id=None, name='new age', number=None, mutable=None)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertCurrent(id=None, name='new age', number=8, mutable=None)
|
|
|
|
|
self.instance.mutable = [1,2,3]
|
|
|
|
|
self.assertCurrent(id=None, name='new age', number=8, mutable=[1,2,3])
|
|
|
|
|
self.instance.mutable[1] = 4
|
|
|
|
|
self.assertCurrent(id=None, name='new age', number=8, mutable=[1,4,3])
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertCurrent(id=self.instance.id, name='new age', number=8, mutable=[1,4,3])
|
|
|
|
|
|
|
|
|
|
def test_update_fields(self):
|
|
|
|
|
self.update_instance(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.instance.mutable = [4,5,6]
|
|
|
|
|
self.assertChanged(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
self.instance.save(update_fields=[])
|
|
|
|
|
self.assertChanged(name='retro', number=4, mutable=[1,2,3])
|
|
|
|
|
self.instance.save(update_fields=['name'])
|
|
|
|
|
in_db = self.tracked_class.objects.get(id=self.instance.id)
|
|
|
|
|
self.assertEqual(in_db.name, self.instance.name)
|
|
|
|
|
self.assertNotEqual(in_db.number, self.instance.number)
|
|
|
|
|
self.assertChanged(number=4, mutable=[1,2,3])
|
|
|
|
|
self.instance.save(update_fields=['number'])
|
|
|
|
|
self.assertChanged(mutable=[1,2,3])
|
|
|
|
|
self.instance.save(update_fields=['mutable'])
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
in_db = self.tracked_class.objects.get(id=self.instance.id)
|
|
|
|
|
self.assertEqual(in_db.name, self.instance.name)
|
|
|
|
|
self.assertEqual(in_db.number, self.instance.number)
|
|
|
|
|
self.assertEqual(in_db.mutable, self.instance.mutable)
|
|
|
|
|
|
|
|
|
|
def test_with_deferred(self):
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.instance.number = 1
|
|
|
|
|
self.instance.save()
|
2018-02-09 19:39:14 +00:00
|
|
|
item = self.tracked_class.objects.only('name').first()
|
2018-04-03 22:43:29 +00:00
|
|
|
if django.VERSION >= (1, 10):
|
|
|
|
|
self.assertTrue(item.get_deferred_fields())
|
|
|
|
|
else:
|
|
|
|
|
self.assertTrue(item._deferred_fields)
|
2016-11-23 23:49:53 +00:00
|
|
|
|
2018-02-09 19:39:14 +00:00
|
|
|
# has_changed() returns False for deferred fields, without un-deferring them.
|
|
|
|
|
# Use an if because ModelTracked doesn't support has_changed() in this case.
|
|
|
|
|
if self.tracked_class == Tracked:
|
2018-06-28 21:08:03 +00:00
|
|
|
self.assertFalse(item.tracker.has_changed('number'))
|
2018-06-21 19:51:16 +00:00
|
|
|
if django.VERSION >= (1, 10):
|
2018-06-29 00:04:57 +00:00
|
|
|
self.assertIsInstance(item.__class__.number, DescriptorWrapper)
|
2018-06-21 19:51:16 +00:00
|
|
|
self.assertTrue('number' in item.get_deferred_fields())
|
|
|
|
|
else:
|
|
|
|
|
self.assertTrue('number' in item._deferred_fields)
|
2016-11-23 23:49:53 +00:00
|
|
|
|
2018-02-09 19:39:14 +00:00
|
|
|
# previous() un-defers field and returns value
|
|
|
|
|
self.assertEqual(item.tracker.previous('number'), 1)
|
2018-06-21 20:07:13 +00:00
|
|
|
if django.VERSION >= (1, 10):
|
|
|
|
|
self.assertNotIn('number', item.get_deferred_fields())
|
|
|
|
|
else:
|
|
|
|
|
self.assertNotIn('number', item._deferred_fields)
|
2018-02-09 19:39:14 +00:00
|
|
|
|
|
|
|
|
# examining a deferred field un-defers it
|
|
|
|
|
item = self.tracked_class.objects.only('name').first()
|
2016-11-23 23:49:53 +00:00
|
|
|
self.assertEqual(item.number, 1)
|
2018-04-03 22:43:29 +00:00
|
|
|
if django.VERSION >= (1, 10):
|
|
|
|
|
self.assertTrue('number' not in item.get_deferred_fields())
|
|
|
|
|
else:
|
|
|
|
|
self.assertTrue('number' not in item._deferred_fields)
|
2016-11-23 23:49:53 +00:00
|
|
|
self.assertEqual(item.tracker.previous('number'), 1)
|
|
|
|
|
self.assertFalse(item.tracker.has_changed('number'))
|
|
|
|
|
|
2018-02-09 19:39:14 +00:00
|
|
|
# has_changed() returns correct values after deferred field is examined
|
|
|
|
|
self.assertFalse(item.tracker.has_changed('number'))
|
2016-11-23 23:49:53 +00:00
|
|
|
item.number = 2
|
|
|
|
|
self.assertTrue(item.tracker.has_changed('number'))
|
|
|
|
|
|
2018-02-09 19:39:14 +00:00
|
|
|
# previous() returns correct value after deferred field is examined
|
|
|
|
|
self.assertEqual(item.tracker.previous('number'), 1)
|
|
|
|
|
|
|
|
|
|
# assigning to a deferred field un-defers it
|
|
|
|
|
# Use an if because ModelTracked doesn't handle this case.
|
|
|
|
|
if self.tracked_class == Tracked:
|
|
|
|
|
|
|
|
|
|
item = self.tracked_class.objects.only('name').first()
|
|
|
|
|
item.number = 2
|
|
|
|
|
|
|
|
|
|
# previous() fetches correct value from database after deferred field is assigned
|
|
|
|
|
self.assertEqual(item.tracker.previous('number'), 1)
|
|
|
|
|
|
|
|
|
|
# database fetch of previous() value doesn't affect current value
|
|
|
|
|
self.assertEqual(item.number, 2)
|
|
|
|
|
|
|
|
|
|
# has_changed() returns correct values after deferred field is assigned
|
|
|
|
|
self.assertTrue(item.tracker.has_changed('number'))
|
|
|
|
|
item.number = 1
|
|
|
|
|
self.assertFalse(item.tracker.has_changed('number'))
|
|
|
|
|
|
|
|
|
|
|
2016-11-23 23:49:53 +00:00
|
|
|
class FieldTrackerMultipleInstancesTests(TestCase):
|
|
|
|
|
|
|
|
|
|
def test_with_deferred_fields_access_multiple(self):
|
|
|
|
|
Tracked.objects.create(pk=1, name='foo', number=1)
|
|
|
|
|
Tracked.objects.create(pk=2, name='bar', number=2)
|
|
|
|
|
|
|
|
|
|
queryset = Tracked.objects.only('id')
|
|
|
|
|
|
|
|
|
|
for instance in queryset:
|
|
|
|
|
instance.name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackedModelCustomTests(FieldTrackerTestCase,
|
|
|
|
|
FieldTrackerCommonTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = TrackedNotDefault
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.instance = self.tracked_class()
|
|
|
|
|
self.tracker = self.instance.name_tracker
|
|
|
|
|
|
|
|
|
|
def test_pre_save_changed(self):
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.name = ''
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
|
|
|
|
|
def test_first_save(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.assertPrevious(name=None, number=None)
|
|
|
|
|
self.assertCurrent(name='')
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.instance.number = 4
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.assertPrevious(name=None, number=None)
|
|
|
|
|
self.assertCurrent(name='retro')
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_has_changed(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.instance.number = 7
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
|
|
|
|
|
def test_post_save_has_changed(self):
|
|
|
|
|
self.update_instance(name='retro', number=4)
|
|
|
|
|
self.assertHasChanged(name=False, number=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.assertHasChanged(name=False, number=None)
|
|
|
|
|
|
|
|
|
|
def test_post_save_previous(self):
|
|
|
|
|
self.update_instance(name='retro', number=4)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertPrevious(name='retro', number=None)
|
|
|
|
|
|
|
|
|
|
def test_post_save_changed(self):
|
|
|
|
|
self.update_instance(name='retro', number=4)
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged(name='retro')
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged(name='retro')
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
|
|
|
|
|
def test_current(self):
|
|
|
|
|
self.assertCurrent(name='')
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertCurrent(name='new age')
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertCurrent(name='new age')
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertCurrent(name='new age')
|
|
|
|
|
|
|
|
|
|
def test_update_fields(self):
|
|
|
|
|
self.update_instance(name='retro', number=4)
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.instance.save(update_fields=['name', 'number'])
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackedModelAttributeTests(FieldTrackerTestCase):
|
|
|
|
|
|
|
|
|
|
tracked_class = TrackedNonFieldAttr
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.instance = self.tracked_class()
|
|
|
|
|
self.tracker = self.instance.tracker
|
|
|
|
|
|
|
|
|
|
def test_previous(self):
|
|
|
|
|
self.assertPrevious(rounded=None)
|
|
|
|
|
self.instance.number = 7.5
|
|
|
|
|
self.assertPrevious(rounded=None)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertPrevious(rounded=8)
|
|
|
|
|
self.instance.number = 7.2
|
|
|
|
|
self.assertPrevious(rounded=8)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertPrevious(rounded=7)
|
|
|
|
|
|
|
|
|
|
def test_has_changed(self):
|
|
|
|
|
self.assertHasChanged(rounded=False)
|
|
|
|
|
self.instance.number = 7.5
|
|
|
|
|
self.assertHasChanged(rounded=True)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertHasChanged(rounded=False)
|
|
|
|
|
self.instance.number = 7.2
|
|
|
|
|
self.assertHasChanged(rounded=True)
|
|
|
|
|
self.instance.number = 7.8
|
|
|
|
|
self.assertHasChanged(rounded=False)
|
|
|
|
|
|
|
|
|
|
def test_changed(self):
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.number = 7.5
|
|
|
|
|
self.assertPrevious(rounded=None)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertPrevious()
|
|
|
|
|
self.instance.number = 7.8
|
|
|
|
|
self.assertPrevious()
|
|
|
|
|
self.instance.number = 7.2
|
|
|
|
|
self.assertPrevious(rounded=8)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertPrevious()
|
|
|
|
|
|
|
|
|
|
def test_current(self):
|
|
|
|
|
self.assertCurrent(rounded=None)
|
|
|
|
|
self.instance.number = 7.5
|
|
|
|
|
self.assertCurrent(rounded=8)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertCurrent(rounded=8)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackedModelMultiTests(FieldTrackerTestCase,
|
|
|
|
|
FieldTrackerCommonTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = TrackedMultiple
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.instance = self.tracked_class()
|
|
|
|
|
self.trackers = [self.instance.name_tracker,
|
|
|
|
|
self.instance.number_tracker]
|
|
|
|
|
|
|
|
|
|
def test_pre_save_changed(self):
|
|
|
|
|
self.tracker = self.instance.name_tracker
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.instance.name = ''
|
|
|
|
|
self.assertChanged(name=None)
|
|
|
|
|
self.tracker = self.instance.number_tracker
|
|
|
|
|
self.assertChanged(number=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged(number=None)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged(number=None)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_has_changed(self):
|
|
|
|
|
self.tracker = self.instance.name_tracker
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=None)
|
|
|
|
|
self.tracker = self.instance.number_tracker
|
|
|
|
|
self.assertHasChanged(name=None, number=False)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=None, number=False)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_previous(self):
|
|
|
|
|
for tracker in self.trackers:
|
|
|
|
|
self.tracker = tracker
|
|
|
|
|
super(FieldTrackedModelMultiTests, self).test_pre_save_previous()
|
|
|
|
|
|
|
|
|
|
def test_post_save_has_changed(self):
|
|
|
|
|
self.update_instance(name='retro', number=4)
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[0], name=False, number=None)
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[1], name=None, number=False)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[0], name=True, number=None)
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[1], name=None, number=False)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[0], name=True, number=None)
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[1], name=None, number=True)
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.instance.number = 4
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[0], name=False, number=None)
|
|
|
|
|
self.assertHasChanged(tracker=self.trackers[1], name=None, number=False)
|
|
|
|
|
|
|
|
|
|
def test_post_save_previous(self):
|
|
|
|
|
self.update_instance(name='retro', number=4)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertPrevious(tracker=self.trackers[0], name='retro', number=None)
|
|
|
|
|
self.assertPrevious(tracker=self.trackers[1], name=None, number=4)
|
|
|
|
|
|
|
|
|
|
def test_post_save_changed(self):
|
|
|
|
|
self.update_instance(name='retro', number=4)
|
|
|
|
|
self.assertChanged(tracker=self.trackers[0])
|
|
|
|
|
self.assertChanged(tracker=self.trackers[1])
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged(tracker=self.trackers[0], name='retro')
|
|
|
|
|
self.assertChanged(tracker=self.trackers[1])
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged(tracker=self.trackers[0], name='retro')
|
|
|
|
|
self.assertChanged(tracker=self.trackers[1], number=4)
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.instance.number = 4
|
|
|
|
|
self.assertChanged(tracker=self.trackers[0])
|
|
|
|
|
self.assertChanged(tracker=self.trackers[1])
|
|
|
|
|
|
|
|
|
|
def test_current(self):
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[0], name='')
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[1], number=None)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[0], name='new age')
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[1], number=None)
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[0], name='new age')
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[1], number=8)
|
|
|
|
|
self.instance.save()
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[0], name='new age')
|
|
|
|
|
self.assertCurrent(tracker=self.trackers[1], number=8)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackerForeignKeyTests(FieldTrackerTestCase):
|
|
|
|
|
|
|
|
|
|
fk_class = Tracked
|
|
|
|
|
tracked_class = TrackedFK
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.old_fk = self.fk_class.objects.create(number=8)
|
|
|
|
|
self.instance = self.tracked_class.objects.create(fk=self.old_fk)
|
|
|
|
|
|
|
|
|
|
def test_default(self):
|
|
|
|
|
self.tracker = self.instance.tracker
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.assertPrevious()
|
|
|
|
|
self.assertCurrent(id=self.instance.id, fk_id=self.old_fk.id)
|
|
|
|
|
self.instance.fk = self.fk_class.objects.create(number=8)
|
|
|
|
|
self.assertChanged(fk_id=self.old_fk.id)
|
|
|
|
|
self.assertPrevious(fk_id=self.old_fk.id)
|
|
|
|
|
self.assertCurrent(id=self.instance.id, fk_id=self.instance.fk_id)
|
|
|
|
|
|
|
|
|
|
def test_custom(self):
|
|
|
|
|
self.tracker = self.instance.custom_tracker
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.assertPrevious()
|
|
|
|
|
self.assertCurrent(fk_id=self.old_fk.id)
|
|
|
|
|
self.instance.fk = self.fk_class.objects.create(number=8)
|
|
|
|
|
self.assertChanged(fk_id=self.old_fk.id)
|
|
|
|
|
self.assertPrevious(fk_id=self.old_fk.id)
|
|
|
|
|
self.assertCurrent(fk_id=self.instance.fk_id)
|
|
|
|
|
|
|
|
|
|
def test_custom_without_id(self):
|
|
|
|
|
with self.assertNumQueries(1):
|
|
|
|
|
self.tracked_class.objects.get()
|
|
|
|
|
self.tracker = self.instance.custom_tracker_without_id
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.assertPrevious()
|
|
|
|
|
self.assertCurrent(fk=self.old_fk.id)
|
|
|
|
|
self.instance.fk = self.fk_class.objects.create(number=8)
|
|
|
|
|
self.assertChanged(fk=self.old_fk.id)
|
|
|
|
|
self.assertPrevious(fk=self.old_fk.id)
|
|
|
|
|
self.assertCurrent(fk=self.instance.fk_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InheritedFieldTrackerTests(FieldTrackerTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = InheritedTracked
|
|
|
|
|
|
|
|
|
|
def test_child_fields_not_tracked(self):
|
|
|
|
|
self.name2 = 'test'
|
|
|
|
|
self.assertEqual(self.tracker.previous('name2'), None)
|
|
|
|
|
self.assertRaises(FieldError, self.tracker.has_changed, 'name2')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackerInheritedForeignKeyTests(FieldTrackerForeignKeyTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = InheritedTrackedFK
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldTrackerFileFieldTests(FieldTrackerTestCase):
|
|
|
|
|
|
|
|
|
|
tracked_class = TrackedFileField
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.instance = self.tracked_class()
|
|
|
|
|
self.tracker = self.instance.tracker
|
|
|
|
|
self.some_file = 'something.txt'
|
|
|
|
|
self.another_file = 'another.txt'
|
|
|
|
|
|
|
|
|
|
def test_pre_save_changed(self):
|
|
|
|
|
self.assertChanged(some_file=None)
|
|
|
|
|
self.instance.some_file = self.some_file
|
|
|
|
|
self.assertChanged(some_file=None)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_has_changed(self):
|
|
|
|
|
self.assertHasChanged(some_file=True)
|
|
|
|
|
self.instance.some_file = self.some_file
|
|
|
|
|
self.assertHasChanged(some_file=True)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_previous(self):
|
|
|
|
|
self.assertPrevious(some_file=None)
|
|
|
|
|
self.instance.some_file = self.some_file
|
|
|
|
|
self.assertPrevious(some_file=None)
|
|
|
|
|
|
|
|
|
|
def test_post_save_changed(self):
|
|
|
|
|
self.update_instance(some_file=self.some_file)
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
previous_file = self.instance.some_file
|
|
|
|
|
self.instance.some_file = self.another_file
|
|
|
|
|
self.assertChanged(some_file=previous_file)
|
|
|
|
|
# test deferred file field
|
|
|
|
|
deferred_instance = self.tracked_class.objects.defer('some_file')[0]
|
|
|
|
|
deferred_instance.some_file # access field to fetch from database
|
|
|
|
|
self.assertChanged(tracker=deferred_instance.tracker)
|
|
|
|
|
|
|
|
|
|
previous_file = deferred_instance.some_file
|
|
|
|
|
deferred_instance.some_file = self.another_file
|
|
|
|
|
self.assertChanged(
|
|
|
|
|
tracker=deferred_instance.tracker,
|
|
|
|
|
some_file=previous_file,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_post_save_has_changed(self):
|
|
|
|
|
self.update_instance(some_file=self.some_file)
|
|
|
|
|
self.assertHasChanged(some_file=False)
|
|
|
|
|
self.instance.some_file = self.another_file
|
|
|
|
|
self.assertHasChanged(some_file=True)
|
|
|
|
|
|
|
|
|
|
# test deferred file field
|
|
|
|
|
deferred_instance = self.tracked_class.objects.defer('some_file')[0]
|
|
|
|
|
deferred_instance.some_file # access field to fetch from database
|
|
|
|
|
self.assertHasChanged(
|
|
|
|
|
tracker=deferred_instance.tracker,
|
|
|
|
|
some_file=False,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
deferred_instance.some_file = self.another_file
|
|
|
|
|
self.assertHasChanged(
|
|
|
|
|
tracker=deferred_instance.tracker,
|
|
|
|
|
some_file=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_post_save_previous(self):
|
|
|
|
|
self.update_instance(some_file=self.some_file)
|
|
|
|
|
previous_file = self.instance.some_file
|
|
|
|
|
self.instance.some_file = self.another_file
|
|
|
|
|
self.assertPrevious(some_file=previous_file)
|
|
|
|
|
|
|
|
|
|
# test deferred file field
|
|
|
|
|
deferred_instance = self.tracked_class.objects.defer('some_file')[0]
|
|
|
|
|
deferred_instance.some_file # access field to fetch from database
|
|
|
|
|
self.assertPrevious(
|
|
|
|
|
tracker=deferred_instance.tracker,
|
|
|
|
|
some_file=previous_file,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
deferred_instance.some_file = self.another_file
|
|
|
|
|
self.assertPrevious(
|
|
|
|
|
tracker=deferred_instance.tracker,
|
|
|
|
|
some_file=previous_file,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_current(self):
|
|
|
|
|
self.assertCurrent(some_file=self.instance.some_file, id=None)
|
|
|
|
|
self.instance.some_file = self.some_file
|
|
|
|
|
self.assertCurrent(some_file=self.instance.some_file, id=None)
|
|
|
|
|
|
|
|
|
|
# test deferred file field
|
|
|
|
|
self.instance.save()
|
|
|
|
|
deferred_instance = self.tracked_class.objects.defer('some_file')[0]
|
|
|
|
|
deferred_instance.some_file # access field to fetch from database
|
|
|
|
|
self.assertCurrent(
|
|
|
|
|
some_file=self.instance.some_file,
|
|
|
|
|
id=self.instance.id,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
self.instance.some_file = self.another_file
|
|
|
|
|
self.assertCurrent(
|
|
|
|
|
some_file=self.instance.some_file,
|
|
|
|
|
id=self.instance.id,
|
|
|
|
|
)
|
2016-11-24 21:31:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class ModelTrackerTests(FieldTrackerTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = ModelTracked
|
|
|
|
|
|
|
|
|
|
def test_pre_save_changed(self):
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = ''
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.mutable = [1,2,3]
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
|
|
|
|
|
def test_first_save(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=True, mutable=True)
|
|
|
|
|
self.assertPrevious(name=None, number=None, mutable=None)
|
|
|
|
|
self.assertCurrent(name='', number=None, id=None, mutable=None)
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.instance.number = 4
|
|
|
|
|
self.instance.mutable = [1,2,3]
|
|
|
|
|
self.assertHasChanged(name=True, number=True, mutable=True)
|
|
|
|
|
self.assertPrevious(name=None, number=None, mutable=None)
|
|
|
|
|
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
|
|
|
|
|
self.assertChanged()
|
2016-03-27 00:02:49 +00:00
|
|
|
|
|
|
|
|
self.instance.save(update_fields=[])
|
|
|
|
|
self.assertHasChanged(name=True, number=True, mutable=True)
|
|
|
|
|
self.assertPrevious(name=None, number=None, mutable=None)
|
|
|
|
|
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
|
self.instance.save(update_fields=['number'])
|
2016-11-24 21:31:23 +00:00
|
|
|
|
|
|
|
|
def test_pre_save_has_changed(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.number = 7
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ModelTrackedModelCustomTests(FieldTrackedModelCustomTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = ModelTrackedNotDefault
|
|
|
|
|
|
|
|
|
|
def test_first_save(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.assertPrevious(name=None, number=None)
|
|
|
|
|
self.assertCurrent(name='')
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'retro'
|
|
|
|
|
self.instance.number = 4
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.assertPrevious(name=None, number=None)
|
|
|
|
|
self.assertCurrent(name='retro')
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
|
|
|
|
|
def test_pre_save_has_changed(self):
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.number = 7
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_changed(self):
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = ''
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ModelTrackedModelMultiTests(FieldTrackedModelMultiTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = ModelTrackedMultiple
|
|
|
|
|
|
|
|
|
|
def test_pre_save_has_changed(self):
|
|
|
|
|
self.tracker = self.instance.name_tracker
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.tracker = self.instance.number_tracker
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertHasChanged(name=True, number=True)
|
|
|
|
|
|
|
|
|
|
def test_pre_save_changed(self):
|
|
|
|
|
self.tracker = self.instance.name_tracker
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = ''
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.tracker = self.instance.number_tracker
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.name = 'new age'
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.instance.number = 8
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ModelTrackerForeignKeyTests(FieldTrackerForeignKeyTests):
|
|
|
|
|
|
|
|
|
|
fk_class = ModelTracked
|
|
|
|
|
tracked_class = ModelTrackedFK
|
|
|
|
|
|
|
|
|
|
def test_custom_without_id(self):
|
|
|
|
|
with self.assertNumQueries(2):
|
|
|
|
|
self.tracked_class.objects.get()
|
|
|
|
|
self.tracker = self.instance.custom_tracker_without_id
|
|
|
|
|
self.assertChanged()
|
|
|
|
|
self.assertPrevious()
|
|
|
|
|
self.assertCurrent(fk=self.old_fk)
|
|
|
|
|
self.instance.fk = self.fk_class.objects.create(number=8)
|
|
|
|
|
self.assertNotEqual(self.instance.fk, self.old_fk)
|
|
|
|
|
self.assertChanged(fk=self.old_fk)
|
|
|
|
|
self.assertPrevious(fk=self.old_fk)
|
|
|
|
|
self.assertCurrent(fk=self.instance.fk)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InheritedModelTrackerTests(ModelTrackerTests):
|
|
|
|
|
|
|
|
|
|
tracked_class = InheritedModelTracked
|
|
|
|
|
|
|
|
|
|
def test_child_fields_not_tracked(self):
|
|
|
|
|
self.name2 = 'test'
|
|
|
|
|
self.assertEqual(self.tracker.previous('name2'), None)
|
|
|
|
|
self.assertTrue(self.tracker.has_changed('name2'))
|