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
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:
return
if any(LOOKUP_SEP in f for f in fields):

View File

@ -735,3 +735,27 @@ class ModelRefreshTests(TestCase):
article.save()
featured.refresh_from_db()
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])