From fbde929b19754f19cba1d14e86f4c59f4b0a633c Mon Sep 17 00:00:00 2001 From: Ben Cail Date: Wed, 26 Oct 2022 09:58:08 -0400 Subject: [PATCH] Fixed #26056 -- Added QuerySet.values()/values_list() support for ArrayField's __overlap lookup. Thanks Mads Jensen and kosz85 and the initial patch. --- django/contrib/postgres/lookups.py | 8 ++++++++ docs/ref/contrib/postgres/fields.txt | 10 +++++++++- docs/releases/4.2.txt | 3 +++ tests/postgres_tests/test_array.py | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/django/contrib/postgres/lookups.py b/django/contrib/postgres/lookups.py index f2f88ebc0ae..4e1783f2883 100644 --- a/django/contrib/postgres/lookups.py +++ b/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" diff --git a/docs/ref/contrib/postgres/fields.txt b/docs/ref/contrib/postgres/fields.txt index 29dbc0db854..31ef0d3982c 100644 --- a/docs/ref/contrib/postgres/fields.txt +++ b/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']) , , ]> + >>> Post.objects.filter(tags__overlap=Post.objects.values_list('tags')) + , , ]> + +.. versionchanged:: 4.2 + + Support for ``QuerySet.values()`` and ``values_list()`` as a right-hand + side was added. + .. fieldlookup:: arrayfield.len ``len`` diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt index cbe42cca99e..8ab9242f978 100644 --- a/docs/releases/4.2.txt +++ b/docs/releases/4.2.txt @@ -102,6 +102,9 @@ Minor features ` 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` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py index 89603e24a01..9e20ab3bafb 100644 --- a/tests/postgres_tests/test_array.py +++ b/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(