/tests/modeltests/expressions/tests.py
Python | 218 lines | 184 code | 18 blank | 16 comment | 0 complexity | a7cbb6148b793378af465e7b870076f0 MD5 | raw file
1from django.core.exceptions import FieldError 2from django.db.models import F 3from django.test import TestCase 4 5from models import Company, Employee 6 7 8class ExpressionsTests(TestCase): 9 def test_filter(self): 10 Company.objects.create( 11 name="Example Inc.", num_employees=2300, num_chairs=5, 12 ceo=Employee.objects.create(firstname="Joe", lastname="Smith") 13 ) 14 Company.objects.create( 15 name="Foobar Ltd.", num_employees=3, num_chairs=4, 16 ceo=Employee.objects.create(firstname="Frank", lastname="Meyer") 17 ) 18 Company.objects.create( 19 name="Test GmbH", num_employees=32, num_chairs=1, 20 ceo=Employee.objects.create(firstname="Max", lastname="Mustermann") 21 ) 22 23 company_query = Company.objects.values( 24 "name", "num_employees", "num_chairs" 25 ).order_by( 26 "name", "num_employees", "num_chairs" 27 ) 28 29 # We can filter for companies where the number of employees is greater 30 # than the number of chairs. 31 self.assertQuerysetEqual( 32 company_query.filter(num_employees__gt=F("num_chairs")), [ 33 { 34 "num_chairs": 5, 35 "name": "Example Inc.", 36 "num_employees": 2300, 37 }, 38 { 39 "num_chairs": 1, 40 "name": "Test GmbH", 41 "num_employees": 32 42 }, 43 ], 44 lambda o: o 45 ) 46 47 # We can set one field to have the value of another field 48 # Make sure we have enough chairs 49 company_query.update(num_chairs=F("num_employees")) 50 self.assertQuerysetEqual( 51 company_query, [ 52 { 53 "num_chairs": 2300, 54 "name": "Example Inc.", 55 "num_employees": 2300 56 }, 57 { 58 "num_chairs": 3, 59 "name": "Foobar Ltd.", 60 "num_employees": 3 61 }, 62 { 63 "num_chairs": 32, 64 "name": "Test GmbH", 65 "num_employees": 32 66 } 67 ], 68 lambda o: o 69 ) 70 71 # We can perform arithmetic operations in expressions 72 # Make sure we have 2 spare chairs 73 company_query.update(num_chairs=F("num_employees")+2) 74 self.assertQuerysetEqual( 75 company_query, [ 76 { 77 'num_chairs': 2302, 78 'name': u'Example Inc.', 79 'num_employees': 2300 80 }, 81 { 82 'num_chairs': 5, 83 'name': u'Foobar Ltd.', 84 'num_employees': 3 85 }, 86 { 87 'num_chairs': 34, 88 'name': u'Test GmbH', 89 'num_employees': 32 90 } 91 ], 92 lambda o: o, 93 ) 94 95 # Law of order of operations is followed 96 company_query.update( 97 num_chairs=F('num_employees') + 2 * F('num_employees') 98 ) 99 self.assertQuerysetEqual( 100 company_query, [ 101 { 102 'num_chairs': 6900, 103 'name': u'Example Inc.', 104 'num_employees': 2300 105 }, 106 { 107 'num_chairs': 9, 108 'name': u'Foobar Ltd.', 109 'num_employees': 3 110 }, 111 { 112 'num_chairs': 96, 113 'name': u'Test GmbH', 114 'num_employees': 32 115 } 116 ], 117 lambda o: o, 118 ) 119 120 # Law of order of operations can be overridden by parentheses 121 company_query.update( 122 num_chairs=((F('num_employees') + 2) * F('num_employees')) 123 ) 124 self.assertQuerysetEqual( 125 company_query, [ 126 { 127 'num_chairs': 5294600, 128 'name': u'Example Inc.', 129 'num_employees': 2300 130 }, 131 { 132 'num_chairs': 15, 133 'name': u'Foobar Ltd.', 134 'num_employees': 3 135 }, 136 { 137 'num_chairs': 1088, 138 'name': u'Test GmbH', 139 'num_employees': 32 140 } 141 ], 142 lambda o: o, 143 ) 144 145 # The relation of a foreign key can become copied over to an other 146 # foreign key. 147 self.assertEqual( 148 Company.objects.update(point_of_contact=F('ceo')), 149 3 150 ) 151 self.assertQuerysetEqual( 152 Company.objects.all(), [ 153 "Joe Smith", 154 "Frank Meyer", 155 "Max Mustermann", 156 ], 157 lambda c: unicode(c.point_of_contact), 158 ) 159 160 c = Company.objects.all()[0] 161 c.point_of_contact = Employee.objects.create(firstname="Guido", lastname="van Rossum") 162 c.save() 163 164 # F Expressions can also span joins 165 self.assertQuerysetEqual( 166 Company.objects.filter(ceo__firstname=F("point_of_contact__firstname")), [ 167 "Foobar Ltd.", 168 "Test GmbH", 169 ], 170 lambda c: c.name 171 ) 172 173 Company.objects.exclude( 174 ceo__firstname=F("point_of_contact__firstname") 175 ).update(name="foo") 176 self.assertEqual( 177 Company.objects.exclude( 178 ceo__firstname=F('point_of_contact__firstname') 179 ).get().name, 180 "foo", 181 ) 182 183 self.assertRaises(FieldError, 184 lambda: Company.objects.exclude( 185 ceo__firstname=F('point_of_contact__firstname') 186 ).update(name=F('point_of_contact__lastname')) 187 ) 188 189 # F expressions can be used to update attributes on single objects 190 test_gmbh = Company.objects.get(name="Test GmbH") 191 self.assertEqual(test_gmbh.num_employees, 32) 192 test_gmbh.num_employees = F("num_employees") + 4 193 test_gmbh.save() 194 test_gmbh = Company.objects.get(pk=test_gmbh.pk) 195 self.assertEqual(test_gmbh.num_employees, 36) 196 197 # F expressions cannot be used to update attributes which are foreign 198 # keys, or attributes which involve joins. 199 test_gmbh.point_of_contact = None 200 test_gmbh.save() 201 self.assertTrue(test_gmbh.point_of_contact is None) 202 def test(): 203 test_gmbh.point_of_contact = F("ceo") 204 self.assertRaises(ValueError, test) 205 206 test_gmbh.point_of_contact = test_gmbh.ceo 207 test_gmbh.save() 208 test_gmbh.name = F("ceo__last_name") 209 self.assertRaises(FieldError, test_gmbh.save) 210 211 # F expressions cannot be used to update attributes on objects which do 212 # not yet exist in the database 213 acme = Company( 214 name="The Acme Widget Co.", num_employees=12, num_chairs=5, 215 ceo=test_gmbh.ceo 216 ) 217 acme.num_employees = F("num_employees") + 16 218 self.assertRaises(TypeError, acme.save)