diff options
| author | Anssi Kääriäinen <akaariai@gmail.com> | 2013-08-30 09:41:07 +0300 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2013-08-30 09:41:07 +0300 |
| commit | e973ee6a9879969b8ae05bb7ff681172cc5386a5 (patch) | |
| tree | d144ae6297a03a3e9836f47c4cd4a08e51ad335d /tests/basic | |
| parent | 13be3bfef1441f9f3c9eb3cad21b5ae158fdb874 (diff) | |
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
Diffstat (limited to 'tests/basic')
| -rw-r--r-- | tests/basic/models.py | 5 | ||||
| -rw-r--r-- | tests/basic/tests.py | 60 |
2 files changed, 64 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 611944902a..2204989823 100644 --- a/tests/basic/tests.py +++ b/tests/basic/tests.py @@ -5,6 +5,7 @@ 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.manager import BaseManager from django.db.models.query import QuerySet, EmptyQuerySet, ValuesListQuerySet, MAX_GET_RESULTS @@ -12,7 +13,7 @@ from django.test import TestCase, TransactionTestCase, skipIfDBFeature, skipUnle 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): @@ -806,3 +807,60 @@ class ManagerTest(TestCase): sorted(BaseManager._get_queryset_methods(QuerySet).keys()), sorted(self.QUERYSET_PROXY_METHODS), ) + +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 |
