diff options
| author | Anssi Kääriäinen <akaariai@gmail.com> | 2014-07-05 09:03:52 +0300 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2014-11-28 06:54:00 -0500 |
| commit | c7175fcdfe94be60c04f3b1ceb6d0b2def2b6f09 (patch) | |
| tree | 409248caf9fe722d53eb1d7654176bb8a5f5c631 /tests | |
| parent | 912ad03226687dae91971ebd7e5cf87521f6b0de (diff) | |
Fixed #901 -- Added Model.refresh_from_db() method
Thanks to github aliases dbrgn, carljm, slurms, dfunckt, and timgraham
for reviews.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/basic/tests.py | 59 | ||||
| -rw-r--r-- | tests/defer/models.py | 14 | ||||
| -rw-r--r-- | tests/defer/tests.py | 28 | ||||
| -rw-r--r-- | tests/field_subclassing/tests.py | 6 | ||||
| -rw-r--r-- | tests/multiple_database/tests.py | 18 |
5 files changed, 123 insertions, 2 deletions
diff --git a/tests/basic/tests.py b/tests/basic/tests.py index a10e38f2a4..31e8b724bc 100644 --- a/tests/basic/tests.py +++ b/tests/basic/tests.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals -from datetime import datetime +from datetime import datetime, timedelta import threading from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned @@ -713,3 +713,60 @@ class SelectOnSaveTests(TestCase): asos.save(update_fields=['pub_date']) finally: Article._base_manager.__class__ = orig_class + + +class ModelRefreshTests(TestCase): + def _truncate_ms(self, val): + # MySQL < 5.6.4 removes microseconds from the datetimes which can cause + # problems when comparing the original value to that loaded from DB + return val - timedelta(microseconds=val.microsecond) + + def test_refresh(self): + a = Article.objects.create(pub_date=self._truncate_ms(datetime.now())) + Article.objects.create(pub_date=self._truncate_ms(datetime.now())) + Article.objects.filter(pk=a.pk).update(headline='new headline') + with self.assertNumQueries(1): + a.refresh_from_db() + self.assertEqual(a.headline, 'new headline') + + orig_pub_date = a.pub_date + new_pub_date = a.pub_date + timedelta(10) + Article.objects.update(headline='new headline 2', pub_date=new_pub_date) + with self.assertNumQueries(1): + a.refresh_from_db(fields=['headline']) + self.assertEqual(a.headline, 'new headline 2') + self.assertEqual(a.pub_date, orig_pub_date) + with self.assertNumQueries(1): + a.refresh_from_db() + self.assertEqual(a.pub_date, new_pub_date) + + def test_refresh_fk(self): + s1 = SelfRef.objects.create() + s2 = SelfRef.objects.create() + s3 = SelfRef.objects.create(selfref=s1) + s3_copy = SelfRef.objects.get(pk=s3.pk) + s3_copy.selfref.touched = True + s3.selfref = s2 + s3.save() + with self.assertNumQueries(1): + s3_copy.refresh_from_db() + with self.assertNumQueries(1): + # The old related instance was thrown away (the selfref_id has + # changed). It needs to be reloaded on access, so one query + # executed. + self.assertFalse(hasattr(s3_copy.selfref, 'touched')) + self.assertEqual(s3_copy.selfref, s2) + + def test_refresh_unsaved(self): + pub_date = self._truncate_ms(datetime.now()) + a = Article.objects.create(pub_date=pub_date) + a2 = Article(id=a.pk) + with self.assertNumQueries(1): + a2.refresh_from_db() + self.assertEqual(a2.pub_date, pub_date) + self.assertEqual(a2._state.db, "default") + + def test_refresh_no_fields(self): + a = Article.objects.create(pub_date=self._truncate_ms(datetime.now())) + with self.assertNumQueries(0): + a.refresh_from_db(fields=[]) diff --git a/tests/defer/models.py b/tests/defer/models.py index ffc8a0c2c7..ecf69c0d7f 100644 --- a/tests/defer/models.py +++ b/tests/defer/models.py @@ -32,3 +32,17 @@ class BigChild(Primary): class ChildProxy(Child): class Meta: proxy = True + + +class RefreshPrimaryProxy(Primary): + class Meta: + proxy = True + + def refresh_from_db(self, using=None, fields=None, **kwargs): + # Reloads all deferred fields if any of the fields is deferred. + if fields is not None: + fields = set(fields) + deferred_fields = self.get_deferred_fields() + if fields.intersection(deferred_fields): + fields = fields.union(deferred_fields) + super(RefreshPrimaryProxy, self).refresh_from_db(using, fields, **kwargs) diff --git a/tests/defer/tests.py b/tests/defer/tests.py index 43a088f3e2..597f871cc8 100644 --- a/tests/defer/tests.py +++ b/tests/defer/tests.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals from django.db.models.query_utils import DeferredAttribute, InvalidQuery from django.test import TestCase -from .models import Secondary, Primary, Child, BigChild, ChildProxy +from .models import Secondary, Primary, Child, BigChild, ChildProxy, RefreshPrimaryProxy class DeferTests(TestCase): @@ -189,3 +189,29 @@ class DeferTests(TestCase): s1_defer = Secondary.objects.only('pk').get(pk=s1.pk) self.assertEqual(s1, s1_defer) self.assertEqual(s1_defer, s1) + + def test_refresh_not_loading_deferred_fields(self): + s = Secondary.objects.create() + rf = Primary.objects.create(name='foo', value='bar', related=s) + rf2 = Primary.objects.only('related', 'value').get() + rf.name = 'new foo' + rf.value = 'new bar' + rf.save() + with self.assertNumQueries(1): + rf2.refresh_from_db() + self.assertEqual(rf2.value, 'new bar') + with self.assertNumQueries(1): + self.assertEqual(rf2.name, 'new foo') + + def test_custom_refresh_on_deferred_loading(self): + s = Secondary.objects.create() + rf = RefreshPrimaryProxy.objects.create(name='foo', value='bar', related=s) + rf2 = RefreshPrimaryProxy.objects.only('related').get() + rf.name = 'new foo' + rf.value = 'new bar' + rf.save() + with self.assertNumQueries(1): + # Customized refresh_from_db() reloads all deferred fields on + # access of any of them. + self.assertEqual(rf2.name, 'new foo') + self.assertEqual(rf2.value, 'new bar') diff --git a/tests/field_subclassing/tests.py b/tests/field_subclassing/tests.py index 5c695a455c..9e40d92496 100644 --- a/tests/field_subclassing/tests.py +++ b/tests/field_subclassing/tests.py @@ -11,6 +11,12 @@ from .models import ChoicesModel, DataModel, MyModel, OtherModel class CustomField(TestCase): + def test_refresh(self): + d = DataModel.objects.create(data=[1, 2, 3]) + d.refresh_from_db(fields=['data']) + self.assertIsInstance(d.data, list) + self.assertEqual(d.data, [1, 2, 3]) + def test_defer(self): d = DataModel.objects.create(data=[1, 2, 3]) diff --git a/tests/multiple_database/tests.py b/tests/multiple_database/tests.py index f230311eed..17a1ef90b1 100644 --- a/tests/multiple_database/tests.py +++ b/tests/multiple_database/tests.py @@ -112,6 +112,24 @@ class QueryTestCase(TestCase): title="Dive into Python" ) + def test_refresh(self): + dive = Book() + dive.title = "Dive into Python" + dive = Book() + dive.title = "Dive into Python" + dive.published = datetime.date(2009, 5, 4) + dive.save(using='other') + dive.published = datetime.date(2009, 5, 4) + dive.save(using='other') + dive2 = Book.objects.using('other').get() + dive2.title = "Dive into Python (on default)" + dive2.save(using='default') + dive.refresh_from_db() + self.assertEqual(dive.title, "Dive into Python") + dive.refresh_from_db(using='default') + self.assertEqual(dive.title, "Dive into Python (on default)") + self.assertEqual(dive._state.db, "default") + def test_basic_queries(self): "Queries are constrained to a single database" dive = Book.objects.using('other').create(title="Dive into Python", |
