diff options
| author | Jozef Knaperek <jknaperek@gmail.com> | 2014-07-11 22:11:04 +0200 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2014-11-12 12:53:30 +0200 |
| commit | c56c42b5c01ed774cfa8e044cd372a984608536c (patch) | |
| tree | f04a635b41051a6d6c1f423a954538f4834bce64 | |
| parent | d647764a53a77be89c8d7239d70adcf8343d9f3a (diff) | |
Fixed #22967 -- Made Model._do_update consistent
Made _do_update behave more strictly according to its docs,
including a corner case when specific concurent updates are
executed and select_on_save is set.
| -rw-r--r-- | django/db/models/base.py | 10 | ||||
| -rw-r--r-- | tests/basic/tests.py | 2 |
2 files changed, 9 insertions, 3 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py index d416b65ccf..f2404d40a5 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -757,8 +757,14 @@ class Model(six.with_metaclass(ModelBase)): return update_fields is not None or filtered.exists() if self._meta.select_on_save and not forced_update: if filtered.exists(): - filtered._update(values) - return True + # It may happen that the object is deleted from the DB right after + # this check, causing the subsequent UPDATE to return zero matching + # rows. The same result can occur in some rare cases when the + # database returns zero despite the UPDATE being executed + # successfully (a row is matched and updated). In order to + # distinguish these two cases, the object's existence in the + # database is again checked for if the UPDATE query returns 0. + return filtered._update(values) > 0 or filtered.exists() else: return False return filtered._update(values) > 0 diff --git a/tests/basic/tests.py b/tests/basic/tests.py index 4f3e8a958f..a10e38f2a4 100644 --- a/tests/basic/tests.py +++ b/tests/basic/tests.py @@ -701,7 +701,7 @@ class SelectOnSaveTests(TestCase): try: Article._base_manager.__class__ = FakeManager asos = ArticleSelectOnSave.objects.create(pub_date=datetime.now()) - with self.assertNumQueries(2): + with self.assertNumQueries(3): asos.save() self.assertTrue(FakeQuerySet.called) # This is not wanted behavior, but this is how Django has always |
