Skip to content

Commit

Permalink
Fixed #28834 -- Followed ancestor links on field cache lookup failure.
Browse files Browse the repository at this point in the history
Thanks Tim for the review.
  • Loading branch information
charettes committed Nov 29, 2017
1 parent 746caf3 commit 78c5e7b
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 1 deletion.
16 changes: 16 additions & 0 deletions django/db/models/fields/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ def get_cached_value(self, instance, default=NOT_PROVIDED):
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
Expand Down
1 change: 1 addition & 0 deletions tests/model_inheritance/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
16 changes: 16 additions & 0 deletions tests/model_inheritance/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,22 @@ def test_select_related_defer(self):
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).
Expand Down
2 changes: 1 addition & 1 deletion tests/select_related_onetoone/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def test_follow_inheritance(self):
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):
Expand Down

0 comments on commit 78c5e7b

Please sign in to comment.