From c6b4d62fa2c7f73b87f6ae7e8cf1d64ee5312dc5 Mon Sep 17 00:00:00 2001 From: Ryan Heard Date: Fri, 2 Jul 2021 15:09:13 -0500 Subject: Fixed #29865 -- Added logical XOR support for Q() and querysets. --- docs/ref/models/querysets.txt | 42 ++++++++++++++++++++++++++++++++++++++++-- docs/releases/4.1.txt | 5 +++++ docs/topics/db/queries.txt | 15 ++++++++++----- 3 files changed, 55 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 44950ecf52..8311b63f7e 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -1903,6 +1903,40 @@ SQL equivalent: ``|`` is not a commutative operation, as different (though equivalent) queries may be generated. +XOR (``^``) +~~~~~~~~~~~ + +.. versionadded:: 4.1 + +Combines two ``QuerySet``\s using the SQL ``XOR`` operator. + +The following are equivalent:: + + Model.objects.filter(x=1) ^ Model.objects.filter(y=2) + from django.db.models import Q + Model.objects.filter(Q(x=1) ^ Q(y=2)) + +SQL equivalent: + +.. code-block:: sql + + SELECT ... WHERE x=1 XOR y=2 + +.. note:: + + ``XOR`` is natively supported on MariaDB and MySQL. On other databases, + ``x ^ y ^ ... ^ z`` is converted to an equivalent: + + .. code-block:: sql + + (x OR y OR ... OR z) AND + 1=( + (CASE WHEN x THEN 1 ELSE 0 END) + + (CASE WHEN y THEN 1 ELSE 0 END) + + ... + (CASE WHEN z THEN 1 ELSE 0 END) + + ) + Methods that do not return ``QuerySet``\s ----------------------------------------- @@ -3751,8 +3785,12 @@ A ``Q()`` object represents an SQL condition that can be used in database-related operations. It's similar to how an :class:`F() ` object represents the value of a model field or annotation. They make it possible to define and reuse conditions, and -combine them using operators such as ``|`` (``OR``) and ``&`` (``AND``). See -:ref:`complex-lookups-with-q`. +combine them using operators such as ``|`` (``OR``), ``&`` (``AND``), and ``^`` +(``XOR``). See :ref:`complex-lookups-with-q`. + +.. versionchanged:: 4.1 + + Support for the ``^`` (``XOR``) operator was added. ``Prefetch()`` objects ---------------------- diff --git a/docs/releases/4.1.txt b/docs/releases/4.1.txt index dafee5271f..9e682e6cc2 100644 --- a/docs/releases/4.1.txt +++ b/docs/releases/4.1.txt @@ -273,6 +273,11 @@ Models as the ``chunk_size`` argument is provided. In older versions, no prefetching was done. +* :class:`~django.db.models.Q` objects and querysets can now be combined using + ``^`` as the exclusive or (``XOR``) operator. ``XOR`` is natively supported + on MariaDB and MySQL. For databases that do not support ``XOR``, the query + will be converted to an equivalent using ``AND``, ``OR``, and ``NOT``. + Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index 9e45f66bb5..8118532513 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -1111,8 +1111,8 @@ For example, this ``Q`` object encapsulates a single ``LIKE`` query:: from django.db.models import Q Q(question__startswith='What') -``Q`` objects can be combined using the ``&`` and ``|`` operators. When an -operator is used on two ``Q`` objects, it yields a new ``Q`` object. +``Q`` objects can be combined using the ``&``, ``|``, and ``^`` operators. When +an operator is used on two ``Q`` objects, it yields a new ``Q`` object. For example, this statement yields a single ``Q`` object that represents the "OR" of two ``"question__startswith"`` queries:: @@ -1124,9 +1124,10 @@ This is equivalent to the following SQL ``WHERE`` clause:: WHERE question LIKE 'Who%' OR question LIKE 'What%' You can compose statements of arbitrary complexity by combining ``Q`` objects -with the ``&`` and ``|`` operators and use parenthetical grouping. Also, ``Q`` -objects can be negated using the ``~`` operator, allowing for combined lookups -that combine both a normal query and a negated (``NOT``) query:: +with the ``&``, ``|``, and ``^`` operators and use parenthetical grouping. +Also, ``Q`` objects can be negated using the ``~`` operator, allowing for +combined lookups that combine both a normal query and a negated (``NOT``) +query:: Q(question__startswith='Who') | ~Q(pub_date__year=2005) @@ -1175,6 +1176,10 @@ precede the definition of any keyword arguments. For example:: The :source:`OR lookups examples ` in Django's unit tests show some possible uses of ``Q``. +.. versionchanged:: 4.1 + + Support for the ``^`` (``XOR``) operator was added. + Comparing objects ================= -- cgit v1.3