From a0624f1492cee18174ddb9ad6e56101d23250509 Mon Sep 17 00:00:00 2001 From: joeriddles Date: Thu, 26 Jan 2023 13:17:49 -0800 Subject: [PATCH 1/5] For error on prefetch_related for tracked field --- model_utils/tracker.py | 3 +++ tests/models.py | 8 ++++++++ tests/test_fields/test_field_tracker.py | 24 ++++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/model_utils/tracker.py b/model_utils/tracker.py index 682ed293..c86b27e8 100644 --- a/model_utils/tracker.py +++ b/model_utils/tracker.py @@ -103,6 +103,9 @@ def __set__(self, instance, value): else: instance.__dict__[self.field_name] = value + def __getattr__(self, attr): + return getattr(self.descriptor, attr) + @staticmethod def cls_for_descriptor(descriptor): if hasattr(descriptor, '__delete__'): diff --git a/tests/models.py b/tests/models.py index d785e880..adbf344b 100644 --- a/tests/models.py +++ b/tests/models.py @@ -324,6 +324,14 @@ class ModelTrackedFK(models.Model): custom_tracker_without_id = ModelTracker(fields=['fk']) +class ModelTrackedPrefetchRelatedFK(models.Model): + fk = models.ForeignKey('ModelTrackedFK', on_delete=models.CASCADE) + + tracker = ModelTracked() + custom_tracker = ModelTracker(fields=['fk_id']) + custom_tracker_without_id = ModelTracker(fields=['fk']) + + class ModelTrackedNotDefault(models.Model): name = models.CharField(max_length=20) number = models.IntegerField() diff --git a/tests/test_fields/test_field_tracker.py b/tests/test_fields/test_field_tracker.py index 670e5878..77f3ea01 100644 --- a/tests/test_fields/test_field_tracker.py +++ b/tests/test_fields/test_field_tracker.py @@ -15,6 +15,7 @@ ModelTrackedFK, ModelTrackedMultiple, ModelTrackedNotDefault, + ModelTrackedPrefetchRelatedFK, Tracked, TrackedAbstract, TrackedFileField, @@ -538,6 +539,29 @@ def test_custom_without_id(self): self.assertCurrent(fk=self.instance.fk_id) +class ModelTrackedPrefetchRelatedFKTests(FieldTrackerTestCase): + """Test that using `prefetch_related` on a tracked field does raise a ValueError.""" + + tracked_class = ModelTrackedPrefetchRelatedFK + + def setUp(self): + model_tracked = ModelTracked.objects.create(name="", number=0) + model_tracked_fk = ModelTrackedFK.objects.create(fk=model_tracked) + self.instance = ModelTrackedPrefetchRelatedFK.objects.create(fk=model_tracked_fk) + + def test_default(self): + self.tracker = self.instance.tracker + self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk__fk"))) + + def test_custom(self): + self.tracker = self.instance.custom_tracker + self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk__fk"))) + + def test_custom_without_id(self): + self.tracker = self.instance.custom_tracker_without_id + self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk__fk"))) + + class FieldTrackerTimeStampedTests(FieldTrackerTestCase): fk_class = Tracked From 7e1437b18a06e0a71d15282c3fa89ba99b90d1a8 Mon Sep 17 00:00:00 2001 From: joeriddles Date: Thu, 26 Jan 2023 13:25:51 -0800 Subject: [PATCH 2/5] Add joeriddles to AUTHORS.rst --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 21c822d2..2c875fe5 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -45,6 +45,7 @@ | Jannis Leidel | Javier Garcia Sogo | Jeff Elmore +| Joe Riddle | John Vandenberg | Jonathan Sundqvist | João Amaro From 9d466ffa742592557c04b06a5193d7da16a069fe Mon Sep 17 00:00:00 2001 From: joeriddles Date: Thu, 26 Jan 2023 14:16:29 -0800 Subject: [PATCH 3/5] Add prefetch_related fix to CHANGES.rst --- CHANGES.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 09d39ca2..3ac443a4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,10 @@ Changelog ========= +4.3.2 +----- +- Fix `ValueError` when calling `prefetch_related` for tracked `ForeignKey` fields (Fixes GH-433) + 4.3.1 (2022-11-15) ------------------ From 604c6f0b622f095945f068a5582d350bf9bf609d Mon Sep 17 00:00:00 2001 From: joeriddles Date: Thu, 26 Jan 2023 14:25:09 -0800 Subject: [PATCH 4/5] Remove unnecessary model and simplify tests for prefetch_related --- tests/models.py | 8 -------- tests/test_fields/test_field_tracker.py | 17 ++++++++--------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/tests/models.py b/tests/models.py index adbf344b..d785e880 100644 --- a/tests/models.py +++ b/tests/models.py @@ -324,14 +324,6 @@ class ModelTrackedFK(models.Model): custom_tracker_without_id = ModelTracker(fields=['fk']) -class ModelTrackedPrefetchRelatedFK(models.Model): - fk = models.ForeignKey('ModelTrackedFK', on_delete=models.CASCADE) - - tracker = ModelTracked() - custom_tracker = ModelTracker(fields=['fk_id']) - custom_tracker_without_id = ModelTracker(fields=['fk']) - - class ModelTrackedNotDefault(models.Model): name = models.CharField(max_length=20) number = models.IntegerField() diff --git a/tests/test_fields/test_field_tracker.py b/tests/test_fields/test_field_tracker.py index 77f3ea01..e69807ed 100644 --- a/tests/test_fields/test_field_tracker.py +++ b/tests/test_fields/test_field_tracker.py @@ -15,7 +15,6 @@ ModelTrackedFK, ModelTrackedMultiple, ModelTrackedNotDefault, - ModelTrackedPrefetchRelatedFK, Tracked, TrackedAbstract, TrackedFileField, @@ -539,27 +538,27 @@ def test_custom_without_id(self): self.assertCurrent(fk=self.instance.fk_id) -class ModelTrackedPrefetchRelatedFKTests(FieldTrackerTestCase): +class FieldTrackerForeignKeyPrefetchRelatedTests(FieldTrackerTestCase): """Test that using `prefetch_related` on a tracked field does raise a ValueError.""" - tracked_class = ModelTrackedPrefetchRelatedFK + fk_class = Tracked + tracked_class = TrackedFK def setUp(self): - model_tracked = ModelTracked.objects.create(name="", number=0) - model_tracked_fk = ModelTrackedFK.objects.create(fk=model_tracked) - self.instance = ModelTrackedPrefetchRelatedFK.objects.create(fk=model_tracked_fk) + model_tracked = self.fk_class.objects.create(name="", number=0) + self.instance = self.tracked_class.objects.create(fk=model_tracked) def test_default(self): self.tracker = self.instance.tracker - self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk__fk"))) + self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk"))) def test_custom(self): self.tracker = self.instance.custom_tracker - self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk__fk"))) + self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk"))) def test_custom_without_id(self): self.tracker = self.instance.custom_tracker_without_id - self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk__fk"))) + self.assertIsNotNone(list(self.tracked_class.objects.prefetch_related("fk"))) class FieldTrackerTimeStampedTests(FieldTrackerTestCase): From 103c942ca5a6d41a9e0bdb35d8b5c3f5dcf77f41 Mon Sep 17 00:00:00 2001 From: joeriddles Date: Thu, 26 Jan 2023 14:25:43 -0800 Subject: [PATCH 5/5] Fix docstring for prefetch_related test class --- tests/test_fields/test_field_tracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fields/test_field_tracker.py b/tests/test_fields/test_field_tracker.py index e69807ed..90f23709 100644 --- a/tests/test_fields/test_field_tracker.py +++ b/tests/test_fields/test_field_tracker.py @@ -539,7 +539,7 @@ def test_custom_without_id(self): class FieldTrackerForeignKeyPrefetchRelatedTests(FieldTrackerTestCase): - """Test that using `prefetch_related` on a tracked field does raise a ValueError.""" + """Test that using `prefetch_related` on a tracked field does not raise a ValueError.""" fk_class = Tracked tracked_class = TrackedFK