diff --git a/wagtail/search/backends/elasticsearch7.py b/wagtail/search/backends/elasticsearch7.py index f6e0c1e69a..af425f5c3a 100644 --- a/wagtail/search/backends/elasticsearch7.py +++ b/wagtail/search/backends/elasticsearch7.py @@ -5,7 +5,7 @@ from urllib.parse import urlparse from django.db import DEFAULT_DB_ALIAS, models from django.db.models.sql import Query -from django.db.models.sql.constants import MULTI +from django.db.models.sql.constants import MULTI, SINGLE from django.utils.crypto import get_random_string from elasticsearch import VERSION as ELASTICSEARCH_VERSION from elasticsearch import Elasticsearch, NotFoundError @@ -505,6 +505,13 @@ class Elasticsearch7SearchQueryCompiler(BaseSearchQueryCompiler): } } else: + if isinstance(value, Query): + db_alias = self.queryset._db or DEFAULT_DB_ALIAS + value = value.get_compiler(db_alias).execute_sql(result_type=SINGLE) + # The result is either a tuple with one element or None + if value: + value = value[0] + return { "term": { column_name: value, diff --git a/wagtail/search/tests/test_backends.py b/wagtail/search/tests/test_backends.py index ab84acdeef..1af759eb71 100644 --- a/wagtail/search/tests/test_backends.py +++ b/wagtail/search/tests/test_backends.py @@ -301,6 +301,23 @@ class BackendTests(WagtailTestUtils): [r.title for r in results], ["The Return of the King"] ) + def test_filter_exact_values_list_subquery(self): + protagonist = ( + models.Character.objects.filter(name="Frodo Baggins") + .order_by("novel_id") + .values_list("pk", flat=True)[:1] + ) + + results = self.backend.search( + MATCH_ALL, + models.Novel.objects.filter(protagonist_id=protagonist), + ) + + self.assertUnsortedListEqual( + [r.title for r in results], + ["The Fellowship of the Ring"], + ) + def test_filter_lt(self): results = self.backend.search( MATCH_ALL, models.Book.objects.filter(number_of_pages__lt=440)