Ticket #16211: issue16211+14029-query-expression-extra-operators2.patch
File issue16211+14029-query-expression-extra-operators2.patch, 11.4 KB (added by , 12 years ago) |
---|
-
docs/topics/db/queries.txt
992 992 # THIS WILL RAISE A FieldError 993 993 >>> Entry.objects.update(headline=F('blog__name')) 994 994 995 .. versionadded:: 1.4 996 997 Django also supports the comparison operators ``==``, ``!=``, ``<=``, ``<``, 998 ``>``, ``>=`` and the bitwise negation operator ``~``:: 999 1000 >>> Entry.objects.update(is_heavily_quoted=~(F('n_pingbacks') < 100)) 1001 995 1002 .. _topics-db-queries-related: 996 1003 997 1004 Related objects -
django/db/models/expressions.py
18 18 AND = '&' 19 19 OR = '|' 20 20 21 # Unary operator (needs special attention in combine_expression) 22 NOT = 'NOT' 23 24 # Comparison operators 25 EQ = '=' 26 GE = '>=' 27 GT = '>' 28 LE = '<=' 29 LT = '<' 30 NE = '<>' 31 21 32 def __init__(self, children=None, connector=None, negated=False): 22 33 if children is not None and len(children) > 1 and connector is None: 23 34 raise TypeError('You have to specify a connector.') … … 91 102 def __ror__(self, other): 92 103 return self._combine(other, self.OR, True) 93 104 105 def __invert__(self): 106 obj = ExpressionNode([self], connector=self.NOT, negated=True) 107 return obj 108 109 def __eq__(self, other): 110 return self._combine(other, self.EQ, False) 111 112 def __ge__(self, other): 113 return self._combine(other, self.GE, False) 114 115 def __gt__(self, other): 116 return self._combine(other, self.GT, False) 117 118 def __le__(self, other): 119 return self._combine(other, self.LE, False) 120 121 def __lt__(self, other): 122 return self._combine(other, self.LT, False) 123 124 def __ne__(self, other): 125 return self._combine(other, self.NE, False) 126 127 def __nonzero__(self): 128 raise TypeError('Boolean operators should be avoided. Use bitwise operators.') 129 94 130 def prepare_database_save(self, unused): 95 131 return self 96 132 -
django/db/backends/__init__.py
863 863 can vary between backends (e.g., Oracle with %% and &) and between 864 864 subexpression types (e.g., date expressions) 865 865 """ 866 if connector == 'NOT': 867 assert len(sub_expressions) == 1 868 return 'NOT (%s)' % sub_expressions[0] 866 869 conn = ' %s ' % connector 867 870 return conn.join(sub_expressions) 868 871 -
django/utils/tree.py
87 87 Otherwise, the whole tree is pushed down one level and a new root 88 88 connector is created, connecting the existing tree and the new node. 89 89 """ 90 if node in self.children and conn_type == self.connector: 91 return 90 # Using for loop with 'is' instead of 'if node in children' so node 91 # __eq__ method doesn't get called 92 for child in self.children: 93 if node is child and conn_type == self.connector: 94 return 92 95 if len(self.children) < 2: 93 96 self.connector = conn_type 94 97 if self.connector == conn_type: -
tests/modeltests/expressions/tests.py
10 10 class ExpressionsTests(TestCase): 11 11 def test_filter(self): 12 12 Company.objects.create( 13 name="Example Inc.", num_employees=2300, num_chairs=5, 13 name="Example Inc.", num_employees=2300, num_chairs=5, is_large=False, 14 14 ceo=Employee.objects.create(firstname="Joe", lastname="Smith") 15 15 ) 16 16 Company.objects.create( 17 name="Foobar Ltd.", num_employees=3, num_chairs=4, 17 name="Foobar Ltd.", num_employees=3, num_chairs=4, is_large=False, 18 18 ceo=Employee.objects.create(firstname="Frank", lastname="Meyer") 19 19 ) 20 20 Company.objects.create( 21 name="Test GmbH", num_employees=32, num_chairs=1, 21 name="Test GmbH", num_employees=32, num_chairs=1, is_large=False, 22 22 ceo=Employee.objects.create(firstname="Max", lastname="Mustermann") 23 23 ) 24 24 25 25 company_query = Company.objects.values( 26 "name", "num_employees", "num_chairs" 26 "name", "num_employees", "num_chairs", "is_large" 27 27 ).order_by( 28 "name", "num_employees", "num_chairs" 28 "name", "num_employees", "num_chairs", "is_large" 29 29 ) 30 30 31 31 # We can filter for companies where the number of employees is greater … … 36 36 "num_chairs": 5, 37 37 "name": "Example Inc.", 38 38 "num_employees": 2300, 39 "is_large": False 39 40 }, 40 41 { 41 42 "num_chairs": 1, 42 43 "name": "Test GmbH", 43 "num_employees": 32 44 "num_employees": 32, 45 "is_large": False 44 46 }, 45 47 ], 46 48 lambda o: o … … 54 56 { 55 57 "num_chairs": 2300, 56 58 "name": "Example Inc.", 57 "num_employees": 2300 59 "num_employees": 2300, 60 "is_large": False 58 61 }, 59 62 { 60 63 "num_chairs": 3, 61 64 "name": "Foobar Ltd.", 62 "num_employees": 3 65 "num_employees": 3, 66 "is_large": False 63 67 }, 64 68 { 65 69 "num_chairs": 32, 66 70 "name": "Test GmbH", 67 "num_employees": 32 71 "num_employees": 32, 72 "is_large": False 68 73 } 69 74 ], 70 75 lambda o: o … … 78 83 { 79 84 'num_chairs': 2302, 80 85 'name': u'Example Inc.', 81 'num_employees': 2300 86 'num_employees': 2300, 87 'is_large': False 82 88 }, 83 89 { 84 90 'num_chairs': 5, 85 91 'name': u'Foobar Ltd.', 86 'num_employees': 3 92 'num_employees': 3, 93 'is_large': False 87 94 }, 88 95 { 89 96 'num_chairs': 34, 90 97 'name': u'Test GmbH', 91 'num_employees': 32 98 'num_employees': 32, 99 'is_large': False 92 100 } 93 101 ], 94 102 lambda o: o, … … 103 111 { 104 112 'num_chairs': 6900, 105 113 'name': u'Example Inc.', 106 'num_employees': 2300 114 'num_employees': 2300, 115 'is_large': False 107 116 }, 108 117 { 109 118 'num_chairs': 9, 110 119 'name': u'Foobar Ltd.', 111 'num_employees': 3 120 'num_employees': 3, 121 'is_large': False 112 122 }, 113 123 { 114 124 'num_chairs': 96, 115 125 'name': u'Test GmbH', 116 'num_employees': 32 126 'num_employees': 32, 127 'is_large': False 117 128 } 118 129 ], 119 130 lambda o: o, … … 128 139 { 129 140 'num_chairs': 5294600, 130 141 'name': u'Example Inc.', 131 'num_employees': 2300 142 'num_employees': 2300, 143 'is_large': False 132 144 }, 133 145 { 134 146 'num_chairs': 15, 135 147 'name': u'Foobar Ltd.', 136 'num_employees': 3 148 'num_employees': 3, 149 'is_large': False 137 150 }, 138 151 { 139 152 'num_chairs': 1088, 140 153 'name': u'Test GmbH', 141 'num_employees': 32 154 'num_employees': 32, 155 'is_large': False 142 156 } 143 157 ], 144 158 lambda o: o, 145 159 ) 146 160 161 # The comparison operators and the bitwise unary not can be used 162 # to assign to boolean fields 163 for expression in ( 164 # Check boundaries 165 ~(F('num_employees') < 33), 166 ~(F('num_employees') <= 32), 167 (F('num_employees') > 2299), 168 (F('num_employees') >= 2300), 169 (F('num_employees') == 2300), 170 ((F('num_employees') + 1 != 4) & (32 != F('num_employees'))), 171 # Inverted argument order works too 172 (2299 < F('num_employees')), 173 (2300 <= F('num_employees')) 174 ): 175 # Test update by F-expression 176 company_query.update( 177 is_large=expression 178 ) 179 # Compare results 180 self.assertQuerysetEqual( 181 company_query, [ 182 { 183 'num_chairs': 5294600, 184 'name': u'Example Inc.', 185 'num_employees': 2300, 186 'is_large': True 187 }, 188 { 189 'num_chairs': 15, 190 'name': u'Foobar Ltd.', 191 'num_employees': 3, 192 'is_large': False 193 }, 194 { 195 'num_chairs': 1088, 196 'name': u'Test GmbH', 197 'num_employees': 32, 198 'is_large': False 199 } 200 ], 201 lambda o: o, 202 ) 203 # Reset values 204 company_query.update( 205 is_large=False 206 ) 207 208 # The python boolean operators should be avoided as they yield 209 # unexpected results 210 test_gmbh = Company.objects.get(name="Test GmbH") 211 def test(): 212 test_gmbh.is_large = not F('is_large') 213 self.assertRaises(TypeError, test) 214 def test(): 215 test_gmbh.is_large = F('is_large') and F('is_large') 216 self.assertRaises(TypeError, test) 217 def test(): 218 test_gmbh.is_large = F('is_large') or F('is_large') 219 self.assertRaises(TypeError, test) 220 147 221 # The relation of a foreign key can become copied over to an other 148 222 # foreign key. 149 223 self.assertEqual( -
tests/modeltests/expressions/models.py
23 23 Employee, 24 24 related_name='company_point_of_contact_set', 25 25 null=True) 26 is_large = models.BooleanField( 27 blank=True) 26 28 27 29 def __unicode__(self): 28 30 return self.name