summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaulo <commonzenpython@gmail.com>2017-09-20 23:27:04 -0500
committerTim Graham <timograham@gmail.com>2017-11-09 11:40:34 -0500
commitee49306176a2d2f1751cb890bd607d42c7c09196 (patch)
treef79ff9ba8642a33f0720f6ac0ff684e038367091
parentebb998976e2889c669972ed3d1b372cc6a2b5229 (diff)
Fixed #27710 -- Made Model.save() invalidate cached, stale relations after a primary key assignment.
-rw-r--r--django/db/models/base.py4
-rw-r--r--tests/many_to_one/tests.py10
-rw-r--r--tests/one_to_one/tests.py10
3 files changed, 24 insertions, 0 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index e8ef2db913..3f4d65571d 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -674,6 +674,10 @@ class Model(metaclass=ModelBase):
"save() prohibited to prevent data loss due to "
"unsaved related object '%s'." % field.name
)
+ # If the relationship's pk was changed, clear the cached
+ # relationship.
+ if obj and obj.pk != getattr(self, field.attname):
+ field.delete_cached_value(self)
using = using or router.db_for_write(self.__class__, instance=self)
if force_insert and (force_update or update_fields):
diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py
index 0e3395bf3a..a2ff587ab3 100644
--- a/tests/many_to_one/tests.py
+++ b/tests/many_to_one/tests.py
@@ -656,3 +656,13 @@ class ManyToOneTests(TestCase):
self.assertEqual(city.districts.count(), 2)
city.districts.remove(d2)
self.assertEqual(city.districts.count(), 1)
+
+ def test_cached_relation_invalidated_on_save(self):
+ """
+ Model.save() invalidates stale ForeignKey relations after a primary key
+ assignment.
+ """
+ self.assertEqual(self.a.reporter, self.r) # caches a.reporter
+ self.a.reporter_id = self.r2.pk
+ self.a.save()
+ self.assertEqual(self.a.reporter, self.r2)
diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py
index 314c56a60f..a3c84a9980 100644
--- a/tests/one_to_one/tests.py
+++ b/tests/one_to_one/tests.py
@@ -507,3 +507,13 @@ class OneToOneTests(TestCase):
pointer = ToFieldPointer.objects.create(target=target)
self.assertSequenceEqual(ToFieldPointer.objects.filter(target=target), [pointer])
self.assertSequenceEqual(ToFieldPointer.objects.filter(pk__exact=pointer), [pointer])
+
+ def test_cached_relation_invalidated_on_save(self):
+ """
+ Model.save() invalidates stale OneToOneField relations after a primary
+ key assignment.
+ """
+ self.assertEqual(self.b1.place, self.p1) # caches b1.place
+ self.b1.place_id = self.p2.pk
+ self.b1.save()
+ self.assertEqual(self.b1.place, self.p2)