summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2017-11-23 02:14:32 -0500
committerSimon Charette <charette.s@gmail.com>2017-11-29 01:28:39 -0500
commit78c5e7b90eee10067d39a8ba6588e6b53ba00d82 (patch)
treebd69ad87bc72eea2d2dcf95b3541579b243d5c51
parent746caf3ef821dbf7588797cb2600fa81b9df9d1d (diff)
Fixed #28834 -- Followed ancestor links on field cache lookup failure.
Thanks Tim for the review.
-rw-r--r--django/db/models/fields/mixins.py16
-rw-r--r--tests/model_inheritance/models.py1
-rw-r--r--tests/model_inheritance/tests.py16
-rw-r--r--tests/select_related_onetoone/tests.py2
4 files changed, 34 insertions, 1 deletions
diff --git a/django/db/models/fields/mixins.py b/django/db/models/fields/mixins.py
index c6dbc4ec5e..f79b7b0c6e 100644
--- a/django/db/models/fields/mixins.py
+++ b/django/db/models/fields/mixins.py
@@ -12,6 +12,22 @@ class FieldCacheMixin:
try:
return instance._state.fields_cache[cache_name]
except KeyError:
+ # An ancestor link will exist if this field is defined on a
+ # multi-table inheritance parent of the instance's class.
+ ancestor_link = instance._meta.get_ancestor_link(self.model)
+ if ancestor_link:
+ try:
+ # The value might be cached on an ancestor if the instance
+ # originated from walking down the inheritance chain.
+ ancestor = ancestor_link.get_cached_value(instance)
+ except KeyError:
+ pass
+ else:
+ value = self.get_cached_value(ancestor)
+ # Cache the ancestor value locally to speed up future
+ # lookups.
+ self.set_cached_value(instance, value)
+ return value
if default is NOT_PROVIDED:
raise
return default
diff --git a/tests/model_inheritance/models.py b/tests/model_inheritance/models.py
index a542385d60..a4f9cfe696 100644
--- a/tests/model_inheritance/models.py
+++ b/tests/model_inheritance/models.py
@@ -178,6 +178,7 @@ class GrandParent(models.Model):
first_name = models.CharField(max_length=80)
last_name = models.CharField(max_length=80)
email = models.EmailField(unique=True)
+ place = models.ForeignKey(Place, models.CASCADE, null=True, related_name='+')
class Meta:
unique_together = ('first_name', 'last_name')
diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py
index 88f1e623c4..ad85a653d5 100644
--- a/tests/model_inheritance/tests.py
+++ b/tests/model_inheritance/tests.py
@@ -368,6 +368,22 @@ class ModelInheritanceDataTests(TestCase):
self.assertEqual(qs[1].italianrestaurant.name, 'Ristorante Miron')
self.assertEqual(qs[1].italianrestaurant.rating, 4)
+ def test_parent_cache_reuse(self):
+ place = Place.objects.create()
+ GrandChild.objects.create(place=place)
+ grand_parent = GrandParent.objects.latest('pk')
+ with self.assertNumQueries(1):
+ self.assertEqual(grand_parent.place, place)
+ parent = grand_parent.parent
+ with self.assertNumQueries(0):
+ self.assertEqual(parent.place, place)
+ child = parent.child
+ with self.assertNumQueries(0):
+ self.assertEqual(child.place, place)
+ grandchild = child.grandchild
+ with self.assertNumQueries(0):
+ self.assertEqual(grandchild.place, place)
+
def test_update_query_counts(self):
"""
Update queries do not generate unnecessary queries (#18304).
diff --git a/tests/select_related_onetoone/tests.py b/tests/select_related_onetoone/tests.py
index 089a1062d9..992de98217 100644
--- a/tests/select_related_onetoone/tests.py
+++ b/tests/select_related_onetoone/tests.py
@@ -82,7 +82,7 @@ class ReverseSelectRelatedTestCase(TestCase):
stat = UserStat.objects.select_related('user', 'advanceduserstat').get(posts=200)
self.assertEqual(stat.advanceduserstat.posts, 200)
self.assertEqual(stat.user.username, 'bob')
- with self.assertNumQueries(1):
+ with self.assertNumQueries(0):
self.assertEqual(stat.advanceduserstat.user.username, 'bob')
def test_nullable_relation(self):