summaryrefslogtreecommitdiff
path: root/tests/basic
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2013-08-30 09:41:07 +0300
committerAnssi Kääriäinen <akaariai@gmail.com>2013-08-30 09:47:34 +0300
commit76e38a21777243fec58c640d617bb71a251c5ba1 (patch)
tree5a14a0f8c788649a97fffac96ed487c853fee603 /tests/basic
parentcd10e998b6a8f9daaf2e25cad55f33f3df51ea88 (diff)
[1.6.x] Fixed #20988 -- Added model meta option select_on_save
The option can be used to force pre 1.6 style SELECT on save behaviour. This is needed in case the database returns zero updated rows even if there is a matching row in the DB. One such case is PostgreSQL update trigger that returns NULL. Reviewed by Tim Graham. Refs #16649 Backport of e973ee6a9879969b8ae05bb7ff681172cc5386a5 from master Conflicts: django/db/models/options.py tests/basic/tests.py
Diffstat (limited to 'tests/basic')
-rw-r--r--tests/basic/models.py5
-rw-r--r--tests/basic/tests.py61
2 files changed, 65 insertions, 1 deletions
diff --git a/tests/basic/models.py b/tests/basic/models.py
index 1bffcb9cda..ee44c1658a 100644
--- a/tests/basic/models.py
+++ b/tests/basic/models.py
@@ -19,6 +19,11 @@ class Article(models.Model):
def __str__(self):
return self.headline
+class ArticleSelectOnSave(Article):
+ class Meta:
+ proxy = True
+ select_on_save = True
+
@python_2_unicode_compatible
class SelfRef(models.Model):
selfref = models.ForeignKey('self', null=True, blank=True,
diff --git a/tests/basic/tests.py b/tests/basic/tests.py
index 4b79c47be5..d8c0964288 100644
--- a/tests/basic/tests.py
+++ b/tests/basic/tests.py
@@ -5,13 +5,14 @@ import threading
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db import connections, DEFAULT_DB_ALIAS
+from django.db import DatabaseError
from django.db.models.fields import Field, FieldDoesNotExist
from django.db.models.query import QuerySet, EmptyQuerySet, ValuesListQuerySet
from django.test import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils import six
from django.utils.translation import ugettext_lazy
-from .models import Article, SelfRef
+from .models import Article, SelfRef, ArticleSelectOnSave
class ModelTest(TestCase):
@@ -712,3 +713,61 @@ class ConcurrentSaveTests(TransactionTestCase):
t.join()
a.save()
self.assertEqual(Article.objects.get(pk=a.pk).headline, 'foo')
+
+
+class SelectOnSaveTests(TestCase):
+ def test_select_on_save(self):
+ a1 = Article.objects.create(pub_date=datetime.now())
+ with self.assertNumQueries(1):
+ a1.save()
+ asos = ArticleSelectOnSave.objects.create(pub_date=datetime.now())
+ with self.assertNumQueries(2):
+ asos.save()
+ with self.assertNumQueries(1):
+ asos.save(force_update=True)
+ Article.objects.all().delete()
+ with self.assertRaises(DatabaseError):
+ with self.assertNumQueries(1):
+ asos.save(force_update=True)
+
+ def test_select_on_save_lying_update(self):
+ """
+ Test that select_on_save works correctly if the database
+ doesn't return correct information about matched rows from
+ UPDATE.
+ """
+ # Change the manager to not return "row matched" for update().
+ # We are going to change the Article's _base_manager class
+ # dynamically. This is a bit of a hack, but it seems hard to
+ # test this properly otherwise. Article's manager, because
+ # proxy models use their parent model's _base_manager.
+
+ orig_class = Article._base_manager.__class__
+
+ class FakeQuerySet(QuerySet):
+ # Make sure the _update method below is in fact called.
+ called = False
+
+ def _update(self, *args, **kwargs):
+ FakeQuerySet.called = True
+ super(FakeQuerySet, self)._update(*args, **kwargs)
+ return 0
+
+ class FakeManager(orig_class):
+ def get_queryset(self):
+ return FakeQuerySet(self.model)
+ try:
+ Article._base_manager.__class__ = FakeManager
+ asos = ArticleSelectOnSave.objects.create(pub_date=datetime.now())
+ with self.assertNumQueries(2):
+ asos.save()
+ self.assertTrue(FakeQuerySet.called)
+ # This is not wanted behaviour, but this is how Django has always
+ # behaved for databases that do not return correct information
+ # about matched rows for UPDATE.
+ with self.assertRaises(DatabaseError):
+ asos.save(force_update=True)
+ with self.assertRaises(DatabaseError):
+ asos.save(update_fields=['pub_date'])
+ finally:
+ Article._base_manager.__class__ = orig_class