Browse Source

Fixed #29076 -- Made Model.refresh_from_db() clear cached relationships even if the related id doesn't change.

Jon Dufresne 7 years ago
parent
commit
136bf5c214
3 changed files with 15 additions and 12 deletions
  1. 2 6
      django/db/models/base.py
  2. 1 6
      docs/ref/models/instances.txt
  3. 12 0
      tests/basic/tests.py

+ 2 - 6
django/db/models/base.py

@@ -609,13 +609,9 @@ class Model(metaclass=ModelBase):
                 # This field wasn't refreshed - skip ahead.
                 continue
             setattr(self, field.attname, getattr(db_instance, field.attname))
-            # Throw away stale foreign key references.
+            # Clear cached foreign keys.
             if field.is_relation and field.is_cached(self):
-                rel_instance = field.get_cached_value(self)
-                local_val = getattr(db_instance, field.attname)
-                related_val = None if rel_instance is None else getattr(rel_instance, field.target_field.attname)
-                if local_val != related_val or (local_val is None and related_val is None):
-                    field.delete_cached_value(self)
+                field.delete_cached_value(self)
 
         # Clear cached relations.
         for field in self._meta.related_objects:

+ 1 - 6
docs/ref/models/instances.txt

@@ -137,12 +137,7 @@ following is done:
 
 1. All non-deferred fields of the model are updated to the values currently
    present in the database.
-2. The previously loaded related instances for which the relation's value is no
-   longer valid are removed from the reloaded instance. For example, if you have
-   a foreign key from the reloaded instance to another model with name
-   ``Author``, then if ``obj.author_id != obj.author.id``, ``obj.author`` will
-   be thrown away, and when next accessed it will be reloaded with the value of
-   ``obj.author_id``.
+2. Any cached relations are cleared from the reloaded instance.
 
 Only fields of the model are reloaded from the database. Other
 database-dependent values such as annotations aren't reloaded. Any

+ 12 - 0
tests/basic/tests.py

@@ -722,3 +722,15 @@ class ModelRefreshTests(TestCase):
         FeaturedArticle.objects.create(article_id=article.pk)
         article.refresh_from_db()
         self.assertTrue(hasattr(article, 'featured'))
+
+    def test_refresh_clears_one_to_one_field(self):
+        article = Article.objects.create(
+            headline='Parrot programs in Python',
+            pub_date=datetime(2005, 7, 28),
+        )
+        featured = FeaturedArticle.objects.create(article_id=article.pk)
+        self.assertEqual(featured.article.headline, 'Parrot programs in Python')
+        article.headline = 'Parrot programs in Python 2.0'
+        article.save()
+        featured.refresh_from_db()
+        self.assertEqual(featured.article.headline, 'Parrot programs in Python 2.0')