Fixed #28834 -- Followed ancestor links on field cache lookup failure.
Thanks Tim for the review.
This commit is contained in:
parent
746caf3ef8
commit
78c5e7b90e
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue