Skip to content

Commit 2f6b096

Browse files
adamchainzsarahboyce
authored andcommitted
Fixed #35950 -- Restored refreshing of relations when fields deferred.
Thank you to Simon Charette and Sarah Boyce for the review. Regression in 73df8b5.
1 parent 32b9e00 commit 2f6b096

File tree

4 files changed

+31
-9
lines changed

4 files changed

+31
-9
lines changed

django/db/models/base.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -726,12 +726,13 @@ def refresh_from_db(self, using=None, fields=None, from_queryset=None):
726726
if fields is not None:
727727
db_instance_qs = db_instance_qs.only(*fields)
728728
elif deferred_fields:
729-
fields = {
730-
f.attname
731-
for f in self._meta.concrete_fields
732-
if f.attname not in deferred_fields
733-
}
734-
db_instance_qs = db_instance_qs.only(*fields)
729+
db_instance_qs = db_instance_qs.only(
730+
*{
731+
f.attname
732+
for f in self._meta.concrete_fields
733+
if f.attname not in deferred_fields
734+
}
735+
)
735736

736737
db_instance = db_instance_qs.get()
737738
non_loaded_fields = db_instance.get_deferred_fields()
@@ -748,9 +749,9 @@ def refresh_from_db(self, using=None, fields=None, from_queryset=None):
748749
field.delete_cached_value(self)
749750

750751
# Clear cached relations.
751-
for field in self._meta.related_objects:
752-
if (fields is None or field.name in fields) and field.is_cached(self):
753-
field.delete_cached_value(self)
752+
for rel in self._meta.related_objects:
753+
if (fields is None or rel.name in fields) and rel.is_cached(self):
754+
rel.delete_cached_value(self)
754755

755756
# Clear cached private relations.
756757
for field in self._meta.private_fields:

docs/releases/5.1.4.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ Bugfixes
1212

1313
* Fixed a crash in ``createsuperuser`` on Python 3.13+ caused by an unhandled
1414
``OSError`` when the username could not be determined (:ticket:`35942`).
15+
16+
* Fixed a regression in Django 5.1 where relational fields were not updated
17+
when calling ``Model.refresh_from_db()`` on instances with deferred fields
18+
(:ticket:`35950`).

tests/contenttypes_tests/test_fields.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ def test_clear_cached_generic_relation_explicit_fields(self):
5757
self.assertIsNot(answer.question, old_question_obj)
5858
self.assertEqual(answer.question, old_question_obj)
5959

60+
def test_clear_cached_generic_relation_when_deferred(self):
61+
question = Question.objects.create(text="question")
62+
Answer.objects.create(text="answer", question=question)
63+
answer = Answer.objects.defer("text").get()
64+
old_question_obj = answer.question
65+
# The reverse relation is refreshed even when the text field is deferred.
66+
answer.refresh_from_db()
67+
self.assertIsNot(answer.question, old_question_obj)
68+
6069

6170
class GenericRelationTests(TestCase):
6271
def test_value_to_string(self):

tests/defer/tests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,14 @@ def test_custom_refresh_on_deferred_loading(self):
290290
self.assertEqual(rf2.name, "new foo")
291291
self.assertEqual(rf2.value, "new bar")
292292

293+
def test_refresh_when_one_field_deferred(self):
294+
s = Secondary.objects.create()
295+
PrimaryOneToOne.objects.create(name="foo", value="bar", related=s)
296+
s = Secondary.objects.defer("first").get()
297+
p_before = s.primary_o2o
298+
s.refresh_from_db()
299+
self.assertIsNot(s.primary_o2o, p_before)
300+
293301

294302
class InvalidDeferTests(SimpleTestCase):
295303
def test_invalid_defer(self):

0 commit comments

Comments
 (0)