/tests/modeltests/defer/tests.py
Python | 137 lines | 98 code | 21 blank | 18 comment | 3 complexity | 98aa4d7feff93dad6c81d6d9506efba7 MD5 | raw file
Possible License(s): BSD-3-Clause
1from django.db.models.query_utils import DeferredAttribute 2from django.test import TestCase 3 4from models import Secondary, Primary, Child, BigChild 5 6 7class DeferTests(TestCase): 8 def assert_delayed(self, obj, num): 9 count = 0 10 for field in obj._meta.fields: 11 if isinstance(obj.__class__.__dict__.get(field.attname), 12 DeferredAttribute): 13 count += 1 14 self.assertEqual(count, num) 15 16 def test_defer(self): 17 # To all outward appearances, instances with deferred fields look the 18 # same as normal instances when we examine attribute values. Therefore 19 # we test for the number of deferred fields on returned instances (by 20 # poking at the internals), as a way to observe what is going on. 21 22 s1 = Secondary.objects.create(first="x1", second="y1") 23 p1 = Primary.objects.create(name="p1", value="xx", related=s1) 24 25 qs = Primary.objects.all() 26 27 self.assert_delayed(qs.defer("name")[0], 1) 28 self.assert_delayed(qs.only("name")[0], 2) 29 self.assert_delayed(qs.defer("related__first")[0], 0) 30 31 obj = qs.select_related().only("related__first")[0] 32 self.assert_delayed(obj, 2) 33 34 self.assertEqual(obj.related_id, s1.pk) 35 36 self.assert_delayed(qs.defer("name").extra(select={"a": 1})[0], 1) 37 self.assert_delayed(qs.extra(select={"a": 1}).defer("name")[0], 1) 38 self.assert_delayed(qs.defer("name").defer("value")[0], 2) 39 self.assert_delayed(qs.only("name").only("value")[0], 2) 40 self.assert_delayed(qs.only("name").defer("value")[0], 2) 41 self.assert_delayed(qs.only("name", "value").defer("value")[0], 2) 42 self.assert_delayed(qs.defer("name").only("value")[0], 2) 43 44 obj = qs.only()[0] 45 self.assert_delayed(qs.defer(None)[0], 0) 46 self.assert_delayed(qs.only("name").defer(None)[0], 0) 47 48 # User values() won't defer anything (you get the full list of 49 # dictionaries back), but it still works. 50 self.assertEqual(qs.defer("name").values()[0], { 51 "id": p1.id, 52 "name": "p1", 53 "value": "xx", 54 "related_id": s1.id, 55 }) 56 self.assertEqual(qs.only("name").values()[0], { 57 "id": p1.id, 58 "name": "p1", 59 "value": "xx", 60 "related_id": s1.id, 61 }) 62 63 # Using defer() and only() with get() is also valid. 64 self.assert_delayed(qs.defer("name").get(pk=p1.pk), 1) 65 self.assert_delayed(qs.only("name").get(pk=p1.pk), 2) 66 67 # DOES THIS WORK? 68 self.assert_delayed(qs.only("name").select_related("related")[0], 1) 69 self.assert_delayed(qs.defer("related").select_related("related")[0], 0) 70 71 # Saving models with deferred fields is possible (but inefficient, 72 # since every field has to be retrieved first). 73 obj = Primary.objects.defer("value").get(name="p1") 74 obj.name = "a new name" 75 obj.save() 76 self.assertQuerysetEqual( 77 Primary.objects.all(), [ 78 "a new name", 79 ], 80 lambda p: p.name 81 ) 82 83 # Regression for #10572 - A subclass with no extra fields can defer 84 # fields from the base class 85 Child.objects.create(name="c1", value="foo", related=s1) 86 # You can defer a field on a baseclass when the subclass has no fields 87 obj = Child.objects.defer("value").get(name="c1") 88 self.assert_delayed(obj, 1) 89 self.assertEqual(obj.name, "c1") 90 self.assertEqual(obj.value, "foo") 91 obj.name = "c2" 92 obj.save() 93 94 # You can retrive a single column on a base class with no fields 95 obj = Child.objects.only("name").get(name="c2") 96 self.assert_delayed(obj, 3) 97 self.assertEqual(obj.name, "c2") 98 self.assertEqual(obj.value, "foo") 99 obj.name = "cc" 100 obj.save() 101 102 BigChild.objects.create(name="b1", value="foo", related=s1, other="bar") 103 # You can defer a field on a baseclass 104 obj = BigChild.objects.defer("value").get(name="b1") 105 self.assert_delayed(obj, 1) 106 self.assertEqual(obj.name, "b1") 107 self.assertEqual(obj.value, "foo") 108 self.assertEqual(obj.other, "bar") 109 obj.name = "b2" 110 obj.save() 111 112 # You can defer a field on a subclass 113 obj = BigChild.objects.defer("other").get(name="b2") 114 self.assert_delayed(obj, 1) 115 self.assertEqual(obj.name, "b2") 116 self.assertEqual(obj.value, "foo") 117 self.assertEqual(obj.other, "bar") 118 obj.name = "b3" 119 obj.save() 120 121 # You can retrieve a single field on a baseclass 122 obj = BigChild.objects.only("name").get(name="b3") 123 self.assert_delayed(obj, 4) 124 self.assertEqual(obj.name, "b3") 125 self.assertEqual(obj.value, "foo") 126 self.assertEqual(obj.other, "bar") 127 obj.name = "b4" 128 obj.save() 129 130 # You can retrieve a single field on a baseclass 131 obj = BigChild.objects.only("other").get(name="b4") 132 self.assert_delayed(obj, 4) 133 self.assertEqual(obj.name, "b4") 134 self.assertEqual(obj.value, "foo") 135 self.assertEqual(obj.other, "bar") 136 obj.name = "bb" 137 obj.save()