summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2012-06-26 18:08:42 +0300
committerAnssi Kääriäinen <akaariai@gmail.com>2012-06-26 18:08:42 +0300
commitb6c356b7bb97f3d6d4831b31e67868313bbbc090 (patch)
tree1cd4c587080703c5b86b13349858509ce145ca4c /tests
parent531878302735e6a2b36d82b584947bbf8eae8111 (diff)
Fixed #17485 -- Made defer work with select_related
This commit tackles a couple of issues. First, in certain cases there were some mixups if field.attname or field.name should be deferred. Field.attname is now always used. Another issue tackled is a case where field is both deferred by .only(), and selected by select_related. This case is now an error. A lot of thanks to koniiiik (Michal Petrucha) for the patch, and to Andrei Antoukh for review.
Diffstat (limited to 'tests')
-rw-r--r--tests/modeltests/defer/tests.py20
-rw-r--r--tests/regressiontests/defer_regress/models.py4
-rw-r--r--tests/regressiontests/defer_regress/tests.py26
-rw-r--r--tests/regressiontests/select_related_regress/tests.py2
4 files changed, 44 insertions, 8 deletions
diff --git a/tests/modeltests/defer/tests.py b/tests/modeltests/defer/tests.py
index eb09162b01..50db5a76b4 100644
--- a/tests/modeltests/defer/tests.py
+++ b/tests/modeltests/defer/tests.py
@@ -1,6 +1,6 @@
from __future__ import absolute_import
-from django.db.models.query_utils import DeferredAttribute
+from django.db.models.query_utils import DeferredAttribute, InvalidQuery
from django.test import TestCase
from .models import Secondary, Primary, Child, BigChild, ChildProxy
@@ -73,9 +73,19 @@ class DeferTests(TestCase):
self.assert_delayed(qs.defer("name").get(pk=p1.pk), 1)
self.assert_delayed(qs.only("name").get(pk=p1.pk), 2)
- # DOES THIS WORK?
- self.assert_delayed(qs.only("name").select_related("related")[0], 1)
- self.assert_delayed(qs.defer("related").select_related("related")[0], 0)
+ # When we defer a field and also select_related it, the query is
+ # invalid and raises an exception.
+ with self.assertRaises(InvalidQuery):
+ qs.only("name").select_related("related")[0]
+ with self.assertRaises(InvalidQuery):
+ qs.defer("related").select_related("related")[0]
+
+ # With a depth-based select_related, all deferred ForeignKeys are
+ # deferred instead of traversed.
+ with self.assertNumQueries(3):
+ obj = qs.defer("related").select_related()[0]
+ self.assert_delayed(obj, 1)
+ self.assertEqual(obj.related.id, s1.pk)
# Saving models with deferred fields is possible (but inefficient,
# since every field has to be retrieved first).
@@ -155,7 +165,7 @@ class DeferTests(TestCase):
children = ChildProxy.objects.all().select_related().only('id', 'name')
self.assertEqual(len(children), 1)
child = children[0]
- self.assert_delayed(child, 1)
+ self.assert_delayed(child, 2)
self.assertEqual(child.name, 'p1')
self.assertEqual(child.value, 'xx')
diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py
index 812d2da206..bd4f845f27 100644
--- a/tests/regressiontests/defer_regress/models.py
+++ b/tests/regressiontests/defer_regress/models.py
@@ -47,3 +47,7 @@ class SimpleItem(models.Model):
class Feature(models.Model):
item = models.ForeignKey(SimpleItem)
+
+class ItemAndSimpleItem(models.Model):
+ item = models.ForeignKey(Item)
+ simple = models.ForeignKey(SimpleItem)
diff --git a/tests/regressiontests/defer_regress/tests.py b/tests/regressiontests/defer_regress/tests.py
index 1f07d4c9a8..53bb59f5b3 100644
--- a/tests/regressiontests/defer_regress/tests.py
+++ b/tests/regressiontests/defer_regress/tests.py
@@ -9,7 +9,7 @@ from django.db.models.loading import cache
from django.test import TestCase
from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy,
- SimpleItem, Feature)
+ SimpleItem, Feature, ItemAndSimpleItem)
class DeferRegressionTest(TestCase):
@@ -109,6 +109,7 @@ class DeferRegressionTest(TestCase):
Child,
Feature,
Item,
+ ItemAndSimpleItem,
Leaf,
Proxy,
RelatedItem,
@@ -125,12 +126,16 @@ class DeferRegressionTest(TestCase):
),
)
)
+ # FIXME: This is dependent on the order in which tests are run --
+ # this test case has to be the first, otherwise a LOT more classes
+ # appear.
self.assertEqual(
klasses, [
"Child",
"Child_Deferred_value",
"Feature",
"Item",
+ "ItemAndSimpleItem",
"Item_Deferred_name",
"Item_Deferred_name_other_value_text",
"Item_Deferred_name_other_value_value",
@@ -139,7 +144,7 @@ class DeferRegressionTest(TestCase):
"Leaf",
"Leaf_Deferred_child_id_second_child_id_value",
"Leaf_Deferred_name_value",
- "Leaf_Deferred_second_child_value",
+ "Leaf_Deferred_second_child_id_value",
"Leaf_Deferred_value",
"Proxy",
"RelatedItem",
@@ -175,6 +180,23 @@ class DeferRegressionTest(TestCase):
self.assertEqual(1, qs.count())
self.assertEqual('Foobar', qs[0].name)
+ def test_defer_with_select_related(self):
+ item1 = Item.objects.create(name="first", value=47)
+ item2 = Item.objects.create(name="second", value=42)
+ simple = SimpleItem.objects.create(name="simple", value="23")
+ related = ItemAndSimpleItem.objects.create(item=item1, simple=simple)
+
+ obj = ItemAndSimpleItem.objects.defer('item').select_related('simple').get()
+ self.assertEqual(obj.item, item1)
+ self.assertEqual(obj.item_id, item1.id)
+
+ obj.item = item2
+ obj.save()
+
+ obj = ItemAndSimpleItem.objects.defer('item').select_related('simple').get()
+ self.assertEqual(obj.item, item2)
+ self.assertEqual(obj.item_id, item2.id)
+
def test_deferred_class_factory(self):
from django.db.models.query_utils import deferred_class_factory
new_class = deferred_class_factory(Item,
diff --git a/tests/regressiontests/select_related_regress/tests.py b/tests/regressiontests/select_related_regress/tests.py
index e35157dbaf..73b0a8a875 100644
--- a/tests/regressiontests/select_related_regress/tests.py
+++ b/tests/regressiontests/select_related_regress/tests.py
@@ -133,7 +133,7 @@ class SelectRelatedRegressTests(TestCase):
self.assertEqual(troy.state.name, 'Western Australia')
# Also works if you use only, rather than defer
- troy = SpecialClient.objects.select_related('state').only('name').get(name='Troy Buswell')
+ troy = SpecialClient.objects.select_related('state').only('name', 'state').get(name='Troy Buswell')
self.assertEqual(troy.name, 'Troy Buswell')
self.assertEqual(troy.value, 42)