Commit b625e827 authored by Anssi Kääriäinen's avatar Anssi Kääriäinen
Browse files

Moved F() '&' and '|' to .bitand() and .bitor()

Done for consistency with Q() expressions and QuerySet combining. This
will allow usage of '&' and '|' as boolean logical operators in the
future. Refs #16211.
parent a8b1861f
Loading
Loading
Loading
Loading
+23 −7
Original line number Diff line number Diff line
@@ -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:
@@ -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)
@@ -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
+6 −0
Original line number Diff line number Diff line
@@ -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
==========================

+12 −0
Original line number Diff line number Diff line
@@ -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
----------------------

+2 −16
Original line number Diff line number Diff line
@@ -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))
@@ -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))
@@ -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):