Skip to content

Commit d8f3714

Browse files
JordanHyattacrawford13
authored andcommitted
Deferred fields patch (django-commons#1393)
* added patch and test * added myself to AUTHORS * adde my change to CHANGES.rst * fixed bug to connect to pre_delete instead of post_delete * implemented suggestion made by @jwaschkau in issue django-commons#1064 * added .python-version to the .gitignore * - added check to signal to see if instance is history enabled before loading its deferred fields * check that fields is "truthy" before calling refresh_from_db * added to test to ensure by-pass logic is covered
1 parent 133d0bc commit d8f3714

File tree

4 files changed

+32
-0
lines changed

4 files changed

+32
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
.idea
77
.tox/
88
.venv/
9+
.python-version
910
/.project
1011
/.pydevproject
1112
/.ve

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Unreleased
77
- Made ``skip_history_when_saving`` work when creating an object - not just when
88
updating an object (gh-1262)
99
- Improved performance of the ``latest_of_each()`` history manager method (gh-1360)
10+
- Fixed issue with deferred fields causing DoesNotExist error (gh-678)
1011
- Added HistoricOneToOneField (gh-1394)
1112

1213
3.7.0 (2024-05-29)

simple_history/models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def finalize(self, sender, **kwargs):
220220
# so the signal handlers can't use weak references.
221221
models.signals.post_save.connect(self.post_save, sender=sender, weak=False)
222222
models.signals.post_delete.connect(self.post_delete, sender=sender, weak=False)
223+
models.signals.pre_delete.connect(self.pre_delete, sender=sender, weak=False)
223224

224225
m2m_fields = self.get_m2m_fields_from_model(sender)
225226

@@ -667,6 +668,23 @@ def post_delete(self, instance, using=None, **kwargs):
667668
else:
668669
self.create_historical_record(instance, "-", using=using)
669670

671+
def pre_delete(self, instance, **kwargs):
672+
"""
673+
pre_delete method to ensure all deferred fileds are loaded on the model
674+
"""
675+
# First check that history is enabled (on model and globally)
676+
if not getattr(settings, "SIMPLE_HISTORY_ENABLED", True):
677+
return
678+
if not hasattr(instance._meta, "simple_history_manager_attribute"):
679+
return
680+
fields = self.fields_included(instance)
681+
field_attrs = {field.attname for field in fields}
682+
deferred_attrs = instance.get_deferred_fields()
683+
# Load all deferred fields that are present in fields_included
684+
fields = field_attrs.intersection(deferred_attrs)
685+
if fields:
686+
instance.refresh_from_db(fields=fields)
687+
670688
def get_change_reason_for_object(self, instance, history_type, using):
671689
"""
672690
Get change reason for object.

simple_history/tests/tests/test_models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,18 @@ def test_history_with_unknown_field(self):
945945
with self.assertNumQueries(0):
946946
new_record.diff_against(old_record, excluded_fields=["unknown_field"])
947947

948+
def test_delete_with_deferred_fields(self):
949+
Poll.objects.create(question="what's up bro?", pub_date=today)
950+
Poll.objects.create(question="what's up sis?", pub_date=today)
951+
Poll.objects.only("id").first().delete()
952+
Poll.objects.defer("question").all().delete()
953+
# Make sure bypass logic runs
954+
Place.objects.create(name="cool place")
955+
Place.objects.defer("name").first().delete()
956+
with self.settings(SIMPLE_HISTORY_ENABLED=False):
957+
Place.objects.create(name="cool place")
958+
Place.objects.defer("name").all().delete()
959+
948960
def test_history_with_custom_queryset(self):
949961
PollWithQuerySetCustomizations.objects.create(
950962
id=1, pub_date=today, question="Question 1"

0 commit comments

Comments
 (0)