diff --git a/model_utils/fields.py b/model_utils/fields.py index 805c707..fe9d4a8 100644 --- a/model_utils/fields.py +++ b/model_utils/fields.py @@ -110,6 +110,9 @@ class MonitorField(models.DateTimeField): return getattr(instance, self.monitor) def _save_initial(self, sender, instance, **kwargs): + if django.VERSION >= (1, 10) and self.monitor in instance.get_deferred_fields(): + # Fix related to issue #241 to avoid recursive error on double monitor fields + return setattr(instance, self.monitor_attname, self.get_monitored_value(instance)) diff --git a/model_utils/tests/models.py b/model_utils/tests/models.py index eee735b..7876828 100644 --- a/model_utils/tests/models.py +++ b/model_utils/tests/models.py @@ -105,6 +105,12 @@ class MonitorWhenEmpty(models.Model): name_changed = MonitorField(monitor="name", when=[]) +class DoubleMonitored(models.Model): + name = models.CharField(max_length=25) + name_changed = MonitorField(monitor="name") + name2 = models.CharField(max_length=25) + name_changed2 = MonitorField(monitor="name2") + class Status(StatusModel): STATUS = Choices( diff --git a/model_utils/tests/tests.py b/model_utils/tests/tests.py index 0c76506..fafef32 100644 --- a/model_utils/tests/tests.py +++ b/model_utils/tests/tests.py @@ -2,6 +2,8 @@ from __future__ import unicode_literals from datetime import datetime, timedelta +from freezegun import freeze_time + try: from unittest import skipUnless except ImportError: # Python 2.6 @@ -33,7 +35,7 @@ from model_utils.tests.models import ( Tracked, TrackedFK, InheritedTrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple, InheritedTracked, TrackedFileField, StatusFieldDefaultFilled, StatusFieldDefaultNotFilled, InheritanceManagerTestChild3, StatusFieldChoicesName, - SoftDeletable) + SoftDeletable, DoubleMonitored) class MigrationsTests(TestCase): @@ -255,6 +257,26 @@ class MonitorWhenEmptyFieldTests(TestCase): self.assertEqual(self.instance.name_changed, self.created) +class MonitorDoubleFieldTests(TestCase): + + def setUp(self): + DoubleMonitored.objects.create(name='Charlie', name2='Charlie2') + + def test_recursion_error_with_only(self): + # Any field passed to only() is generating a recursion error + list(DoubleMonitored.objects.only('id')) + + def test_recursion_error_with_defer(self): + # Only monitored fields passed to defer() are failing + list(DoubleMonitored.objects.defer('name')) + + def test_monitor_still_works_with_deferred_fields_filtered_out_of_save_initial(self): + obj = DoubleMonitored.objects.defer('name').get(name='Charlie') + with freeze_time("2016-12-01"): + obj.name = 'Charlie2' + obj.save() + self.assertEqual(obj.name_changed, datetime(2016, 12, 1)) + class StatusFieldTests(TestCase):