From bcf2086d7a4cac26cd3d9bd5716b08de85db695d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Pode=C5=A1va?= Date: Fri, 14 Apr 2023 11:00:17 +0200 Subject: [PATCH] Fix HistoricForeignKey when used together with prefetch_related() --- CHANGES.rst | 1 + simple_history/models.py | 2 +- simple_history/tests/tests/test_models.py | 93 +++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 68aacc97f..1407e351b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,7 @@ Changes Unreleased ---------- +- Fixed ``HistoricForeignKey`` behaviour when used together with ``prefetch_related()`` 3.3.0 (2023-03-08) ------------------ diff --git a/simple_history/models.py b/simple_history/models.py index db19c66fa..d68c68f61 100644 --- a/simple_history/models.py +++ b/simple_history/models.py @@ -860,7 +860,7 @@ def get_queryset(self): ) else: queryset = super().get_queryset() - return self._apply_rel_filters(queryset) + return queryset return create_reverse_many_to_one_manager( HistoricRelationModelManager, self.rel diff --git a/simple_history/tests/tests/test_models.py b/simple_history/tests/tests/test_models.py index 5dd87aeb8..06e2af112 100644 --- a/simple_history/tests/tests/test_models.py +++ b/simple_history/tests/tests/test_models.py @@ -2545,3 +2545,96 @@ def test_historic_to_historic(self): )[0] pt1i = pt1h.instance self.assertEqual(pt1i.organization.name, "original") + + def test_non_historic_to_historic_prefetch(self): + org1 = TestOrganizationWithHistory.objects.create(name="org1") + org2 = TestOrganizationWithHistory.objects.create(name="org2") + + p1 = TestParticipantToHistoricOrganization.objects.create( + name="p1", organization=org1 + ) + p2 = TestParticipantToHistoricOrganization.objects.create( + name="p2", organization=org1 + ) + p3 = TestParticipantToHistoricOrganization.objects.create( + name="p3", organization=org2 + ) + p4 = TestParticipantToHistoricOrganization.objects.create( + name="p4", organization=org2 + ) + + with self.assertNumQueries(2): + record1, record2 = TestOrganizationWithHistory.objects.prefetch_related( + "participants" + ).all() + + self.assertListEqual( + [p.name for p in record1.participants.all()], + [p1.name, p2.name], + ) + self.assertListEqual( + [p.name for p in record2.participants.all()], + [p3.name, p4.name], + ) + + def test_historic_to_non_historic_prefetch(self): + org1 = TestOrganization.objects.create(name="org1") + org2 = TestOrganization.objects.create(name="org2") + + p1 = TestHistoricParticipantToOrganization.objects.create( + name="p1", organization=org1 + ) + p2 = TestHistoricParticipantToOrganization.objects.create( + name="p2", organization=org1 + ) + p3 = TestHistoricParticipantToOrganization.objects.create( + name="p3", organization=org2 + ) + p4 = TestHistoricParticipantToOrganization.objects.create( + name="p4", organization=org2 + ) + + with self.assertNumQueries(2): + record1, record2 = TestOrganization.objects.prefetch_related( + "participants" + ).all() + + self.assertListEqual( + [p.name for p in record1.participants.all()], + [p1.name, p2.name], + ) + self.assertListEqual( + [p.name for p in record2.participants.all()], + [p3.name, p4.name], + ) + + def test_historic_to_historic_prefetch(self): + org1 = TestOrganizationWithHistory.objects.create(name="org1") + org2 = TestOrganizationWithHistory.objects.create(name="org2") + + p1 = TestHistoricParticipanToHistoricOrganization.objects.create( + name="p1", organization=org1 + ) + p2 = TestHistoricParticipanToHistoricOrganization.objects.create( + name="p2", organization=org1 + ) + p3 = TestHistoricParticipanToHistoricOrganization.objects.create( + name="p3", organization=org2 + ) + p4 = TestHistoricParticipanToHistoricOrganization.objects.create( + name="p4", organization=org2 + ) + + with self.assertNumQueries(2): + record1, record2 = TestOrganizationWithHistory.objects.prefetch_related( + "historic_participants" + ).all() + + self.assertListEqual( + [p.name for p in record1.historic_participants.all()], + [p1.name, p2.name], + ) + self.assertListEqual( + [p.name for p in record2.historic_participants.all()], + [p3.name, p4.name], + )