Loading django/db/models/expressions.py +23 −7 Original line number Diff line number Diff line Loading @@ -14,9 +14,11 @@ class ExpressionNode(tree.Node): # because it can be used in strings that also # have parameter substitution. # Bitwise operators AND = '&' OR = '|' # Bitwise operators - note that these are generated by .bitand() # and .bitor(), the '&' and '|' are reserved for boolean operator # usage. BITAND = '&' BITOR = '|' def __init__(self, children=None, connector=None, negated=False): if children is not None and len(children) > 1 and connector is None: Loading Loading @@ -66,10 +68,20 @@ class ExpressionNode(tree.Node): return self._combine(other, self.MOD, False) def __and__(self, other): return self._combine(other, self.AND, False) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def bitand(self, other): return self._combine(other, self.BITAND, False) def __or__(self, other): return self._combine(other, self.OR, False) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def bitor(self, other): return self._combine(other, self.BITOR, False) def __radd__(self, other): return self._combine(other, self.ADD, True) Loading @@ -88,10 +100,14 @@ class ExpressionNode(tree.Node): return self._combine(other, self.MOD, True) def __rand__(self, other): return self._combine(other, self.AND, True) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def __ror__(self, other): return self._combine(other, self.OR, True) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def prepare_database_save(self, unused): return self Loading docs/releases/1.5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -438,6 +438,12 @@ Miscellaneous needs. The new default value is `0666` (octal) and the current umask value is first masked out. * The :ref:`F() expressions <query-expressions>` supported bitwise operators by ``&`` and ``|``. These operators are now available using ``.bitand()`` and ``.bitor()`` instead. The removal of ``&`` and ``|`` was done to be consistent with :ref:`Q() expressions <complex-lookups-with-q>` and ``QuerySet`` combining where the operators are used as boolean AND and OR operators. Features deprecated in 1.5 ========================== Loading docs/topics/db/queries.txt +12 −0 Original line number Diff line number Diff line Loading @@ -640,6 +640,18 @@ that were modified more than 3 days after they were published:: >>> from datetime import timedelta >>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3)) .. versionadded:: 1.5 ``.bitand()`` and ``.bitor()`` The ``F()`` objects now support bitwise operations by ``.bitand()`` and ``.bitor()``, for example:: >>> F('somefield').bitand(16) .. versionchanged:: 1.5 The previously undocumented operators ``&`` and ``|`` no longer produce bitwise operations, use ``.bitand()`` and ``.bitor()`` instead. The pk lookup shortcut ---------------------- Loading tests/regressiontests/expressions_regress/tests.py +2 −16 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ class ExpressionOperatorTests(TestCase): def test_lefthand_bitwise_and(self): # LH Bitwise ands on integers Number.objects.filter(pk=self.n.pk).update(integer=F('integer') & 56) Number.objects.filter(pk=self.n.pk).update(integer=F('integer').bitand(56)) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 40) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) Loading @@ -136,7 +136,7 @@ class ExpressionOperatorTests(TestCase): @skipUnlessDBFeature('supports_bitwise_or') def test_lefthand_bitwise_or(self): # LH Bitwise or on integers Number.objects.filter(pk=self.n.pk).update(integer=F('integer') | 48) Number.objects.filter(pk=self.n.pk).update(integer=F('integer').bitor(48)) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 58) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) Loading Loading @@ -181,20 +181,6 @@ class ExpressionOperatorTests(TestCase): self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 27) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) def test_right_hand_bitwise_and(self): # RH Bitwise ands on integers Number.objects.filter(pk=self.n.pk).update(integer=15 & F('integer')) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 10) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) @skipUnlessDBFeature('supports_bitwise_or') def test_right_hand_bitwise_or(self): # RH Bitwise or on integers Number.objects.filter(pk=self.n.pk).update(integer=15 | F('integer')) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 47) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) class FTimeDeltaTests(TestCase): Loading Loading
django/db/models/expressions.py +23 −7 Original line number Diff line number Diff line Loading @@ -14,9 +14,11 @@ class ExpressionNode(tree.Node): # because it can be used in strings that also # have parameter substitution. # Bitwise operators AND = '&' OR = '|' # Bitwise operators - note that these are generated by .bitand() # and .bitor(), the '&' and '|' are reserved for boolean operator # usage. BITAND = '&' BITOR = '|' def __init__(self, children=None, connector=None, negated=False): if children is not None and len(children) > 1 and connector is None: Loading Loading @@ -66,10 +68,20 @@ class ExpressionNode(tree.Node): return self._combine(other, self.MOD, False) def __and__(self, other): return self._combine(other, self.AND, False) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def bitand(self, other): return self._combine(other, self.BITAND, False) def __or__(self, other): return self._combine(other, self.OR, False) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def bitor(self, other): return self._combine(other, self.BITOR, False) def __radd__(self, other): return self._combine(other, self.ADD, True) Loading @@ -88,10 +100,14 @@ class ExpressionNode(tree.Node): return self._combine(other, self.MOD, True) def __rand__(self, other): return self._combine(other, self.AND, True) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def __ror__(self, other): return self._combine(other, self.OR, True) raise NotImplementedError( "Use .bitand() and .bitor() for bitwise logical operations." ) def prepare_database_save(self, unused): return self Loading
docs/releases/1.5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -438,6 +438,12 @@ Miscellaneous needs. The new default value is `0666` (octal) and the current umask value is first masked out. * The :ref:`F() expressions <query-expressions>` supported bitwise operators by ``&`` and ``|``. These operators are now available using ``.bitand()`` and ``.bitor()`` instead. The removal of ``&`` and ``|`` was done to be consistent with :ref:`Q() expressions <complex-lookups-with-q>` and ``QuerySet`` combining where the operators are used as boolean AND and OR operators. Features deprecated in 1.5 ========================== Loading
docs/topics/db/queries.txt +12 −0 Original line number Diff line number Diff line Loading @@ -640,6 +640,18 @@ that were modified more than 3 days after they were published:: >>> from datetime import timedelta >>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3)) .. versionadded:: 1.5 ``.bitand()`` and ``.bitor()`` The ``F()`` objects now support bitwise operations by ``.bitand()`` and ``.bitor()``, for example:: >>> F('somefield').bitand(16) .. versionchanged:: 1.5 The previously undocumented operators ``&`` and ``|`` no longer produce bitwise operations, use ``.bitand()`` and ``.bitor()`` instead. The pk lookup shortcut ---------------------- Loading
tests/regressiontests/expressions_regress/tests.py +2 −16 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ class ExpressionOperatorTests(TestCase): def test_lefthand_bitwise_and(self): # LH Bitwise ands on integers Number.objects.filter(pk=self.n.pk).update(integer=F('integer') & 56) Number.objects.filter(pk=self.n.pk).update(integer=F('integer').bitand(56)) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 40) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) Loading @@ -136,7 +136,7 @@ class ExpressionOperatorTests(TestCase): @skipUnlessDBFeature('supports_bitwise_or') def test_lefthand_bitwise_or(self): # LH Bitwise or on integers Number.objects.filter(pk=self.n.pk).update(integer=F('integer') | 48) Number.objects.filter(pk=self.n.pk).update(integer=F('integer').bitor(48)) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 58) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) Loading Loading @@ -181,20 +181,6 @@ class ExpressionOperatorTests(TestCase): self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 27) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) def test_right_hand_bitwise_and(self): # RH Bitwise ands on integers Number.objects.filter(pk=self.n.pk).update(integer=15 & F('integer')) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 10) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) @skipUnlessDBFeature('supports_bitwise_or') def test_right_hand_bitwise_or(self): # RH Bitwise or on integers Number.objects.filter(pk=self.n.pk).update(integer=15 | F('integer')) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 47) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3)) class FTimeDeltaTests(TestCase): Loading