Browse Source

Fixed #34925 -- Prevented Model.refresh_from_db() from mutating list of fields.

trontelj 1 năm trước cách đây
mục cha
commit
b0ec87b857
3 tập tin đã thay đổi với 16 bổ sung5 xóa
  1. 1 1
      django/db/models/base.py
  2. 3 0
      tests/basic/models.py
  3. 12 4
      tests/basic/tests.py

+ 1 - 1
django/db/models/base.py

@@ -691,7 +691,7 @@ class Model(AltersData, metaclass=ModelBase):
             self._prefetched_objects_cache = {}
         else:
             prefetched_objects_cache = getattr(self, "_prefetched_objects_cache", ())
-            for field in fields:
+            for field in list(fields):
                 if field in prefetched_objects_cache:
                     del prefetched_objects_cache[field]
                     fields.remove(field)

+ 3 - 0
tests/basic/models.py

@@ -38,6 +38,9 @@ class SelfRef(models.Model):
         related_name="+",
     )
     article = models.ForeignKey(Article, models.SET_NULL, null=True, blank=True)
+    article_cited = models.ForeignKey(
+        Article, models.SET_NULL, null=True, blank=True, related_name="cited"
+    )
 
     def __str__(self):
         # This method intentionally doesn't work for all cases - part

+ 12 - 4
tests/basic/tests.py

@@ -926,24 +926,32 @@ class ModelRefreshTests(TestCase):
 
     def test_prefetched_cache_cleared(self):
         a = Article.objects.create(pub_date=datetime(2005, 7, 28))
-        s = SelfRef.objects.create(article=a)
+        s = SelfRef.objects.create(article=a, article_cited=a)
         # refresh_from_db() without fields=[...]
-        a1_prefetched = Article.objects.prefetch_related("selfref_set").first()
+        a1_prefetched = Article.objects.prefetch_related("selfref_set", "cited").first()
         self.assertCountEqual(a1_prefetched.selfref_set.all(), [s])
+        self.assertCountEqual(a1_prefetched.cited.all(), [s])
         s.article = None
+        s.article_cited = None
         s.save()
         # Relation is cleared and prefetch cache is stale.
         self.assertCountEqual(a1_prefetched.selfref_set.all(), [s])
+        self.assertCountEqual(a1_prefetched.cited.all(), [s])
         a1_prefetched.refresh_from_db()
         # Cache was cleared and new results are available.
         self.assertCountEqual(a1_prefetched.selfref_set.all(), [])
+        self.assertCountEqual(a1_prefetched.cited.all(), [])
         # refresh_from_db() with fields=[...]
-        a2_prefetched = Article.objects.prefetch_related("selfref_set").first()
+        a2_prefetched = Article.objects.prefetch_related("selfref_set", "cited").first()
         self.assertCountEqual(a2_prefetched.selfref_set.all(), [])
+        self.assertCountEqual(a2_prefetched.cited.all(), [])
         s.article = a
+        s.article_cited = 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"])
+        self.assertCountEqual(a2_prefetched.cited.all(), [])
+        a2_prefetched.refresh_from_db(fields=["selfref_set", "cited"])
         # Cache was cleared and new results are available.
         self.assertCountEqual(a2_prefetched.selfref_set.all(), [s])
+        self.assertCountEqual(a2_prefetched.cited.all(), [s])