summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2014-07-05 09:03:52 +0300
committerTim Graham <timograham@gmail.com>2014-11-28 06:54:00 -0500
commitc7175fcdfe94be60c04f3b1ceb6d0b2def2b6f09 (patch)
tree409248caf9fe722d53eb1d7654176bb8a5f5c631 /tests
parent912ad03226687dae91971ebd7e5cf87521f6b0de (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.py59
-rw-r--r--tests/defer/models.py14
-rw-r--r--tests/defer/tests.py28
-rw-r--r--tests/field_subclassing/tests.py6
-rw-r--r--tests/multiple_database/tests.py18
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",