summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2024-11-30 08:03:55 +0000
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-12-02 16:01:37 +0100
commit2f6b096b83c55317c7ceef2d8d5dc3bee33293dc (patch)
tree7d17909df90c690f26dcda0eaa6b7fb0b54fd35b
parent32b9e00b0c74b3af77c25215e2e2d1254b995355 (diff)
Fixed #35950 -- Restored refreshing of relations when fields deferred.
Thank you to Simon Charette and Sarah Boyce for the review. Regression in 73df8b54a2fab53bec4c7573cda5ad8c869c2fd8.
-rw-r--r--django/db/models/base.py19
-rw-r--r--docs/releases/5.1.4.txt4
-rw-r--r--tests/contenttypes_tests/test_fields.py9
-rw-r--r--tests/defer/tests.py8
4 files changed, 31 insertions, 9 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index a20e88749f..d948cd2a1c 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -726,12 +726,13 @@ class Model(AltersData, metaclass=ModelBase):
if fields is not None:
db_instance_qs = db_instance_qs.only(*fields)
elif deferred_fields:
- fields = {
- f.attname
- for f in self._meta.concrete_fields
- if f.attname not in deferred_fields
- }
- db_instance_qs = db_instance_qs.only(*fields)
+ db_instance_qs = db_instance_qs.only(
+ *{
+ f.attname
+ for f in self._meta.concrete_fields
+ if f.attname not in deferred_fields
+ }
+ )
db_instance = db_instance_qs.get()
non_loaded_fields = db_instance.get_deferred_fields()
@@ -748,9 +749,9 @@ class Model(AltersData, metaclass=ModelBase):
field.delete_cached_value(self)
# Clear cached relations.
- for field in self._meta.related_objects:
- if (fields is None or field.name in fields) and field.is_cached(self):
- field.delete_cached_value(self)
+ for rel in self._meta.related_objects:
+ if (fields is None or rel.name in fields) and rel.is_cached(self):
+ rel.delete_cached_value(self)
# Clear cached private relations.
for field in self._meta.private_fields:
diff --git a/docs/releases/5.1.4.txt b/docs/releases/5.1.4.txt
index 0c21d99566..44950ac76a 100644
--- a/docs/releases/5.1.4.txt
+++ b/docs/releases/5.1.4.txt
@@ -12,3 +12,7 @@ Bugfixes
* Fixed a crash in ``createsuperuser`` on Python 3.13+ caused by an unhandled
``OSError`` when the username could not be determined (:ticket:`35942`).
+
+* Fixed a regression in Django 5.1 where relational fields were not updated
+ when calling ``Model.refresh_from_db()`` on instances with deferred fields
+ (:ticket:`35950`).
diff --git a/tests/contenttypes_tests/test_fields.py b/tests/contenttypes_tests/test_fields.py
index ab16324fb6..fc49d59b27 100644
--- a/tests/contenttypes_tests/test_fields.py
+++ b/tests/contenttypes_tests/test_fields.py
@@ -57,6 +57,15 @@ class GenericForeignKeyTests(TestCase):
self.assertIsNot(answer.question, old_question_obj)
self.assertEqual(answer.question, old_question_obj)
+ def test_clear_cached_generic_relation_when_deferred(self):
+ question = Question.objects.create(text="question")
+ Answer.objects.create(text="answer", question=question)
+ answer = Answer.objects.defer("text").get()
+ old_question_obj = answer.question
+ # The reverse relation is refreshed even when the text field is deferred.
+ answer.refresh_from_db()
+ self.assertIsNot(answer.question, old_question_obj)
+
class GenericRelationTests(TestCase):
def test_value_to_string(self):
diff --git a/tests/defer/tests.py b/tests/defer/tests.py
index 3945b667ba..989b5c63d7 100644
--- a/tests/defer/tests.py
+++ b/tests/defer/tests.py
@@ -290,6 +290,14 @@ class TestDefer2(AssertionMixin, TestCase):
self.assertEqual(rf2.name, "new foo")
self.assertEqual(rf2.value, "new bar")
+ def test_refresh_when_one_field_deferred(self):
+ s = Secondary.objects.create()
+ PrimaryOneToOne.objects.create(name="foo", value="bar", related=s)
+ s = Secondary.objects.defer("first").get()
+ p_before = s.primary_o2o
+ s.refresh_from_db()
+ self.assertIsNot(s.primary_o2o, p_before)
+
class InvalidDeferTests(SimpleTestCase):
def test_invalid_defer(self):