Fixed #29625 -- Made Model.refresh_from_db() clear prefetch related caches.

This commit is contained in:
Ming Qin 2018-08-18 15:33:43 +08:00 committed by Tim Graham
parent d311124be5
commit cfb4845f06
2 changed files with 32 additions and 1 deletions

View File

@ -582,7 +582,14 @@ class Model(metaclass=ModelBase):
When accessing deferred fields of an instance, the deferred loading When accessing deferred fields of an instance, the deferred loading
of the field will call this method. of the field will call this method.
""" """
if fields is not None: if fields is None:
self._prefetched_objects_cache = {}
else:
prefetched_objects_cache = getattr(self, '_prefetched_objects_cache', ())
for field in fields:
if field in prefetched_objects_cache:
del prefetched_objects_cache[field]
fields.remove(field)
if not fields: if not fields:
return return
if any(LOOKUP_SEP in f for f in fields): if any(LOOKUP_SEP in f for f in fields):

View File

@ -735,3 +735,27 @@ class ModelRefreshTests(TestCase):
article.save() article.save()
featured.refresh_from_db() featured.refresh_from_db()
self.assertEqual(featured.article.headline, 'Parrot programs in Python 2.0') self.assertEqual(featured.article.headline, 'Parrot programs in Python 2.0')
def test_prefetched_cache_cleared(self):
a = Article.objects.create(pub_date=datetime(2005, 7, 28))
s = SelfRef.objects.create(article=a)
# refresh_from_db() without fields=[...]
a1_prefetched = Article.objects.prefetch_related('selfref_set').first()
self.assertCountEqual(a1_prefetched.selfref_set.all(), [s])
s.article = None
s.save()
# Relation is cleared and prefetch cache is stale.
self.assertCountEqual(a1_prefetched.selfref_set.all(), [s])
a1_prefetched.refresh_from_db()
# Cache was cleared and new results are available.
self.assertCountEqual(a1_prefetched.selfref_set.all(), [])
# refresh_from_db() with fields=[...]
a2_prefetched = Article.objects.prefetch_related('selfref_set').first()
self.assertCountEqual(a2_prefetched.selfref_set.all(), [])
s.article = a
s.save()
# Relation is added and prefetch cache is stale.
self.assertCountEqual(a2_prefetched.selfref_set.all(), [])
a2_prefetched.refresh_from_db(fields=['selfref_set'])
# Cache was cleared and new results are available.
self.assertCountEqual(a2_prefetched.selfref_set.all(), [s])