mirror of https://github.com/django/django.git
Fixed #35044 -- Avoided clearing reverse relations and private fields when accessing deferred fields.
Regression ina7b5ad8b19
for reverse relations and possibly in123b1d3fcf
for private fields.
This commit is contained in:
parent
74f7fe3f3d
commit
73df8b54a2
|
@ -740,12 +740,16 @@ class Model(AltersData, metaclass=ModelBase):
|
|||
|
||||
# Clear cached relations.
|
||||
for field in self._meta.related_objects:
|
||||
if field.is_cached(self):
|
||||
if (fields is None or field.name in fields) and field.is_cached(self):
|
||||
field.delete_cached_value(self)
|
||||
|
||||
# Clear cached private relations.
|
||||
for field in self._meta.private_fields:
|
||||
if field.is_relation and field.is_cached(self):
|
||||
if (
|
||||
(fields is None or field.name in fields)
|
||||
and field.is_relation
|
||||
and field.is_cached(self)
|
||||
):
|
||||
field.delete_cached_value(self)
|
||||
|
||||
self._state.db = db_instance._state.db
|
||||
|
|
|
@ -45,6 +45,18 @@ class GenericForeignKeyTests(TestCase):
|
|||
new_entity = answer.question
|
||||
self.assertIsNot(old_entity, new_entity)
|
||||
|
||||
def test_clear_cached_generic_relation_explicit_fields(self):
|
||||
question = Question.objects.create(text="question")
|
||||
answer = Answer.objects.create(text="answer", question=question)
|
||||
old_question_obj = answer.question
|
||||
# The reverse relation is not refreshed if not passed explicitly in
|
||||
# `fields`.
|
||||
answer.refresh_from_db(fields=["text"])
|
||||
self.assertIs(answer.question, old_question_obj)
|
||||
answer.refresh_from_db(fields=["question"])
|
||||
self.assertIsNot(answer.question, old_question_obj)
|
||||
self.assertEqual(answer.question, old_question_obj)
|
||||
|
||||
|
||||
class GenericRelationTests(TestCase):
|
||||
def test_value_to_string(self):
|
||||
|
@ -55,6 +67,29 @@ class GenericRelationTests(TestCase):
|
|||
self.assertCountEqual(result, [answer1.pk, answer2.pk])
|
||||
|
||||
|
||||
class DeferredGenericRelationTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.question = Question.objects.create(text="question")
|
||||
cls.answer = Answer.objects.create(text="answer", question=cls.question)
|
||||
|
||||
def test_defer_not_clear_cached_private_relations(self):
|
||||
obj = Answer.objects.defer("text").get(pk=self.answer.pk)
|
||||
with self.assertNumQueries(1):
|
||||
obj.question
|
||||
obj.text # Accessing a deferred field.
|
||||
with self.assertNumQueries(0):
|
||||
obj.question
|
||||
|
||||
def test_only_not_clear_cached_private_relations(self):
|
||||
obj = Answer.objects.only("content_type", "object_id").get(pk=self.answer.pk)
|
||||
with self.assertNumQueries(1):
|
||||
obj.question
|
||||
obj.text # Accessing a deferred field.
|
||||
with self.assertNumQueries(0):
|
||||
obj.question
|
||||
|
||||
|
||||
class GetPrefetchQuerySetDeprecation(TestCase):
|
||||
def test_generic_relation_warning(self):
|
||||
Question.objects.create(text="test")
|
||||
|
|
|
@ -19,6 +19,14 @@ class Primary(models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
class PrimaryOneToOne(models.Model):
|
||||
name = models.CharField(max_length=50)
|
||||
value = models.CharField(max_length=50)
|
||||
related = models.OneToOneField(
|
||||
Secondary, models.CASCADE, related_name="primary_o2o"
|
||||
)
|
||||
|
||||
|
||||
class Child(Primary):
|
||||
pass
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ from .models import (
|
|||
Child,
|
||||
ChildProxy,
|
||||
Primary,
|
||||
PrimaryOneToOne,
|
||||
RefreshPrimaryProxy,
|
||||
Secondary,
|
||||
ShadowChild,
|
||||
|
@ -326,3 +327,28 @@ class InvalidDeferTests(SimpleTestCase):
|
|||
)
|
||||
with self.assertRaisesMessage(FieldError, msg):
|
||||
Primary.objects.only("name").select_related("related")[0]
|
||||
|
||||
|
||||
class DeferredRelationTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.secondary = Secondary.objects.create(first="a", second="b")
|
||||
cls.primary = PrimaryOneToOne.objects.create(
|
||||
name="Bella", value="Baxter", related=cls.secondary
|
||||
)
|
||||
|
||||
def test_defer_not_clear_cached_relations(self):
|
||||
obj = Secondary.objects.defer("first").get(pk=self.secondary.pk)
|
||||
with self.assertNumQueries(1):
|
||||
obj.primary_o2o
|
||||
obj.first # Accessing a deferred field.
|
||||
with self.assertNumQueries(0):
|
||||
obj.primary_o2o
|
||||
|
||||
def test_only_not_clear_cached_relations(self):
|
||||
obj = Secondary.objects.only("first").get(pk=self.secondary.pk)
|
||||
with self.assertNumQueries(1):
|
||||
obj.primary_o2o
|
||||
obj.second # Accessing a deferred field.
|
||||
with self.assertNumQueries(0):
|
||||
obj.primary_o2o
|
||||
|
|
Loading…
Reference in New Issue