Browse Source

Fixed #26056 -- Added QuerySet.values()/values_list() support for ArrayField's __overlap lookup.

Thanks Mads Jensen and kosz85 and the initial patch.
Ben Cail 2 years ago
parent
commit
fbde929b19

+ 8 - 0
django/contrib/postgres/lookups.py

@@ -1,5 +1,6 @@
 from django.db.models import Transform
 from django.db.models.lookups import PostgresOperatorLookup
+from django.db.models.sql.query import Query
 
 from .search import SearchVector, SearchVectorExact, SearchVectorField
 
@@ -18,6 +19,13 @@ class Overlap(PostgresOperatorLookup):
     lookup_name = "overlap"
     postgres_operator = "&&"
 
+    def get_prep_lookup(self):
+        from .expressions import ArraySubquery
+
+        if isinstance(self.rhs, Query):
+            self.rhs = ArraySubquery(self.rhs)
+        return super().get_prep_lookup()
+
 
 class HasKey(PostgresOperatorLookup):
     lookup_name = "has_key"

+ 9 - 1
docs/ref/contrib/postgres/fields.txt

@@ -170,7 +170,7 @@ Returns objects where the data shares any results with the values passed. Uses
 the SQL operator ``&&``. For example::
 
     >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
-    >>> Post.objects.create(name='Second post', tags=['thoughts'])
+    >>> Post.objects.create(name='Second post', tags=['thoughts', 'tutorial'])
     >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
 
     >>> Post.objects.filter(tags__overlap=['thoughts'])
@@ -179,6 +179,14 @@ the SQL operator ``&&``. For example::
     >>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
     <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
 
+    >>> Post.objects.filter(tags__overlap=Post.objects.values_list('tags'))
+    <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
+
+.. versionchanged:: 4.2
+
+    Support for ``QuerySet.values()`` and ``values_list()`` as a right-hand
+    side was added.
+
 .. fieldlookup:: arrayfield.len
 
 ``len``

+ 3 - 0
docs/releases/4.2.txt

@@ -102,6 +102,9 @@ Minor features
   <django.contrib.postgres.search.TrigramStrictWordDistance>` expressions allow
   using trigram strict word similarity.
 
+* The :lookup:`arrayfield.overlap` lookup now supports ``QuerySet.values()``
+  and ``values_list()`` as a right-hand side.
+
 :mod:`django.contrib.redirects`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

+ 15 - 0
tests/postgres_tests/test_array.py

@@ -414,6 +414,21 @@ class TestQuerying(PostgreSQLTestCase):
             [obj_1, obj_2],
         )
 
+    def test_overlap_values(self):
+        qs = NullableIntegerArrayModel.objects.filter(order__lt=3)
+        self.assertCountEqual(
+            NullableIntegerArrayModel.objects.filter(
+                field__overlap=qs.values_list("field"),
+            ),
+            self.objs[:3],
+        )
+        self.assertCountEqual(
+            NullableIntegerArrayModel.objects.filter(
+                field__overlap=qs.values("field"),
+            ),
+            self.objs[:3],
+        )
+
     def test_lookups_autofield_array(self):
         qs = (
             NullableIntegerArrayModel.objects.filter(