Fixed #28834 -- Followed ancestor links on field cache lookup failure.

Thanks Tim for the review.
This commit is contained in:
Simon Charette 2017-11-23 02:14:32 -05:00
parent 746caf3ef8
commit 78c5e7b90e
4 changed files with 34 additions and 1 deletions

View File

@ -12,6 +12,22 @@ class FieldCacheMixin:
try: try:
return instance._state.fields_cache[cache_name] return instance._state.fields_cache[cache_name]
except KeyError: 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: if default is NOT_PROVIDED:
raise raise
return default return default

View File

@ -178,6 +178,7 @@ class GrandParent(models.Model):
first_name = models.CharField(max_length=80) first_name = models.CharField(max_length=80)
last_name = models.CharField(max_length=80) last_name = models.CharField(max_length=80)
email = models.EmailField(unique=True) email = models.EmailField(unique=True)
place = models.ForeignKey(Place, models.CASCADE, null=True, related_name='+')
class Meta: class Meta:
unique_together = ('first_name', 'last_name') unique_together = ('first_name', 'last_name')

View File

@ -368,6 +368,22 @@ class ModelInheritanceDataTests(TestCase):
self.assertEqual(qs[1].italianrestaurant.name, 'Ristorante Miron') self.assertEqual(qs[1].italianrestaurant.name, 'Ristorante Miron')
self.assertEqual(qs[1].italianrestaurant.rating, 4) 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): def test_update_query_counts(self):
""" """
Update queries do not generate unnecessary queries (#18304). Update queries do not generate unnecessary queries (#18304).

View File

@ -82,7 +82,7 @@ class ReverseSelectRelatedTestCase(TestCase):
stat = UserStat.objects.select_related('user', 'advanceduserstat').get(posts=200) stat = UserStat.objects.select_related('user', 'advanceduserstat').get(posts=200)
self.assertEqual(stat.advanceduserstat.posts, 200) self.assertEqual(stat.advanceduserstat.posts, 200)
self.assertEqual(stat.user.username, 'bob') self.assertEqual(stat.user.username, 'bob')
with self.assertNumQueries(1): with self.assertNumQueries(0):
self.assertEqual(stat.advanceduserstat.user.username, 'bob') self.assertEqual(stat.advanceduserstat.user.username, 'bob')
def test_nullable_relation(self): def test_nullable_relation(self):