Ticket #16211: issue16211+14029-query-expression-extra-operators3.diff
File issue16211+14029-query-expression-extra-operators3.diff, 11.6 KB (added by , 12 years ago) |
---|
-
django/db/backends/__init__.py
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 649f807..2939fc5 100644
a b class BaseDatabaseOperations(object): 912 912 can vary between backends (e.g., Oracle with %% and &) and between 913 913 subexpression types (e.g., date expressions) 914 914 """ 915 if connector == 'NOT': 916 assert len(sub_expressions) == 1 917 return 'NOT (%s)' % sub_expressions[0] 915 918 conn = ' %s ' % connector 916 919 return conn.join(sub_expressions) 917 920 -
django/db/models/expressions.py
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index 639ef6e..ac0a8d3 100644
a b class ExpressionNode(tree.Node): 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.') … … class ExpressionNode(tree.Node): 93 104 def __ror__(self, other): 94 105 return self._combine(other, self.OR, True) 95 106 107 def __invert__(self): 108 obj = ExpressionNode([self], connector=self.NOT, negated=True) 109 return obj 110 111 def __eq__(self, other): 112 return self._combine(other, self.EQ, False) 113 114 def __ge__(self, other): 115 return self._combine(other, self.GE, False) 116 117 def __gt__(self, other): 118 return self._combine(other, self.GT, False) 119 120 def __le__(self, other): 121 return self._combine(other, self.LE, False) 122 123 def __lt__(self, other): 124 return self._combine(other, self.LT, False) 125 126 def __ne__(self, other): 127 return self._combine(other, self.NE, False) 128 129 def __nonzero__(self): 130 raise TypeError('Boolean operators should be avoided. Use bitwise operators.') 131 96 132 def prepare_database_save(self, unused): 97 133 return self 98 134 -
django/utils/tree.py
diff --git a/django/utils/tree.py b/django/utils/tree.py index 717181d..090e5c9 100644
a b class Node(object): 88 88 Otherwise, the whole tree is pushed down one level and a new root 89 89 connector is created, connecting the existing tree and the new node. 90 90 """ 91 if node in self.children and conn_type == self.connector: 92 return 91 # Using for loop with 'is' instead of 'if node in children' so node 92 # __eq__ method doesn't get called 93 for child in self.children: 94 if node is child and conn_type == self.connector: 95 return 93 96 if len(self.children) < 2: 94 97 self.connector = conn_type 95 98 if self.connector == conn_type: -
docs/topics/db/queries.txt
diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index b4d4eb1..172f9cc 100644
a b a join with an ``F()`` object, a ``FieldError`` will be raised:: 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 -
tests/modeltests/expressions/models.py
diff --git a/tests/modeltests/expressions/models.py b/tests/modeltests/expressions/models.py index f592a0e..15f0d24 100644
a b class Company(models.Model): 27 27 Employee, 28 28 related_name='company_point_of_contact_set', 29 29 null=True) 30 is_large = models.BooleanField( 31 blank=True) 30 32 31 33 def __str__(self): 32 34 return self.name -
tests/modeltests/expressions/tests.py
diff --git a/tests/modeltests/expressions/tests.py b/tests/modeltests/expressions/tests.py index 99eb07e..66407c7 100644
a b from .models import Company, Employee 11 11 class ExpressionsTests(TestCase): 12 12 def test_filter(self): 13 13 Company.objects.create( 14 name="Example Inc.", num_employees=2300, num_chairs=5, 14 name="Example Inc.", num_employees=2300, num_chairs=5, is_large=False, 15 15 ceo=Employee.objects.create(firstname="Joe", lastname="Smith") 16 16 ) 17 17 Company.objects.create( 18 name="Foobar Ltd.", num_employees=3, num_chairs=4, 18 name="Foobar Ltd.", num_employees=3, num_chairs=4, is_large=False, 19 19 ceo=Employee.objects.create(firstname="Frank", lastname="Meyer") 20 20 ) 21 21 Company.objects.create( 22 name="Test GmbH", num_employees=32, num_chairs=1, 22 name="Test GmbH", num_employees=32, num_chairs=1, is_large=False, 23 23 ceo=Employee.objects.create(firstname="Max", lastname="Mustermann") 24 24 ) 25 25 26 26 company_query = Company.objects.values( 27 "name", "num_employees", "num_chairs" 27 "name", "num_employees", "num_chairs", "is_large" 28 28 ).order_by( 29 "name", "num_employees", "num_chairs" 29 "name", "num_employees", "num_chairs", "is_large" 30 30 ) 31 31 32 32 # We can filter for companies where the number of employees is greater … … class ExpressionsTests(TestCase): 37 37 "num_chairs": 5, 38 38 "name": "Example Inc.", 39 39 "num_employees": 2300, 40 "is_large": False 40 41 }, 41 42 { 42 43 "num_chairs": 1, 43 44 "name": "Test GmbH", 44 "num_employees": 32 45 "num_employees": 32, 46 "is_large": False 45 47 }, 46 48 ], 47 49 lambda o: o … … class ExpressionsTests(TestCase): 55 57 { 56 58 "num_chairs": 2300, 57 59 "name": "Example Inc.", 58 "num_employees": 2300 60 "num_employees": 2300, 61 "is_large": False 59 62 }, 60 63 { 61 64 "num_chairs": 3, 62 65 "name": "Foobar Ltd.", 63 "num_employees": 3 66 "num_employees": 3, 67 "is_large": False 64 68 }, 65 69 { 66 70 "num_chairs": 32, 67 71 "name": "Test GmbH", 68 "num_employees": 32 72 "num_employees": 32, 73 "is_large": False 69 74 } 70 75 ], 71 76 lambda o: o … … class ExpressionsTests(TestCase): 79 84 { 80 85 'num_chairs': 2302, 81 86 'name': 'Example Inc.', 82 'num_employees': 2300 87 'num_employees': 2300, 88 'is_large': False 83 89 }, 84 90 { 85 91 'num_chairs': 5, 86 92 'name': 'Foobar Ltd.', 87 'num_employees': 3 93 'num_employees': 3, 94 'is_large': False 88 95 }, 89 96 { 90 97 'num_chairs': 34, 91 98 'name': 'Test GmbH', 92 'num_employees': 32 99 'num_employees': 32, 100 'is_large': False 93 101 } 94 102 ], 95 103 lambda o: o, … … class ExpressionsTests(TestCase): 104 112 { 105 113 'num_chairs': 6900, 106 114 'name': 'Example Inc.', 107 'num_employees': 2300 115 'num_employees': 2300, 116 'is_large': False 108 117 }, 109 118 { 110 119 'num_chairs': 9, 111 120 'name': 'Foobar Ltd.', 112 'num_employees': 3 121 'num_employees': 3, 122 'is_large': False 113 123 }, 114 124 { 115 125 'num_chairs': 96, 116 126 'name': 'Test GmbH', 117 'num_employees': 32 127 'num_employees': 32, 128 'is_large': False 118 129 } 119 130 ], 120 131 lambda o: o, … … class ExpressionsTests(TestCase): 129 140 { 130 141 'num_chairs': 5294600, 131 142 'name': 'Example Inc.', 132 'num_employees': 2300 143 'num_employees': 2300, 144 'is_large': False 133 145 }, 134 146 { 135 147 'num_chairs': 15, 136 148 'name': 'Foobar Ltd.', 137 'num_employees': 3 149 'num_employees': 3, 150 'is_large': False 138 151 }, 139 152 { 140 153 'num_chairs': 1088, 141 154 'name': 'Test GmbH', 142 'num_employees': 32 155 'num_employees': 32, 156 'is_large': False 143 157 } 144 158 ], 145 159 lambda o: o, 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) 147 220 148 221 # The relation of a foreign key can become copied over to an other 149 222 # foreign key.