From 59626dfc2849267b210087bde13274c74a904cec Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Wed, 11 Sep 2019 11:57:15 +0100 Subject: [PATCH] Fix Postgres search indexing on Postgres 9.4 and Django >=2.2.1 Fixes #5547 As of Django 2.2.1, Value expressions within a SearchVector must specify an output_field: https://code.djangoproject.com/ticket/30446 --- wagtail/contrib/postgres_search/backend.py | 14 +++++++++----- .../contrib/postgres_search/tests/test_backend.py | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/wagtail/contrib/postgres_search/backend.py b/wagtail/contrib/postgres_search/backend.py index e7d13833b..5b3be3b34 100644 --- a/wagtail/contrib/postgres_search/backend.py +++ b/wagtail/contrib/postgres_search/backend.py @@ -19,7 +19,7 @@ from .utils import ( get_content_type_pk, get_descendants_content_types_pks, get_postgresql_connections, get_sql_weights, get_weight, unidecode) -EMPTY_VECTOR = SearchVector(Value('')) +EMPTY_VECTOR = SearchVector(Value('', output_field=TextField())) class Index: @@ -32,6 +32,10 @@ class Index: raise NotSupportedError( 'You must select a PostgreSQL database ' 'to use PostgreSQL search.') + + # Whether to allow adding items via the faster upsert method available in Postgres >=9.5 + self._enable_upsert = (self.connection.pg_version >= 90500) + self.entries = IndexEntry._default_manager.using(self.db_alias) def add_model(self, model): @@ -137,11 +141,11 @@ class Index: ids_and_objs = {} for obj in objs: obj._autocomplete_ = ( - ADD([SearchVector(Value(text), weight=weight, config=config) + ADD([SearchVector(Value(text, output_field=TextField()), weight=weight, config=config) for text, weight in obj._autocomplete_]) if obj._autocomplete_ else EMPTY_VECTOR) obj._body_ = ( - ADD([SearchVector(Value(text), weight=weight, config=config) + ADD([SearchVector(Value(text, output_field=TextField()), weight=weight, config=config) for text, weight in obj._body_]) if obj._body_ else EMPTY_VECTOR) ids_and_objs[obj._object_id_] = obj @@ -173,9 +177,9 @@ class Index: # TODO: Delete unindexed objects while dealing with proxy models. if objs: content_type_pk = get_content_type_pk(model) - # Use a faster method for PostgreSQL >= 9.5 + update_method = ( - self.add_items_upsert if self.connection.pg_version >= 90500 + self.add_items_upsert if self._enable_upsert else self.add_items_update_then_create) update_method(content_type_pk, objs) diff --git a/wagtail/contrib/postgres_search/tests/test_backend.py b/wagtail/contrib/postgres_search/tests/test_backend.py index 01080214f..607d67250 100644 --- a/wagtail/contrib/postgres_search/tests/test_backend.py +++ b/wagtail/contrib/postgres_search/tests/test_backend.py @@ -135,3 +135,17 @@ class TestPostgresSearchBackend(BackendTests, TestCase): # Now the phrase operator. results = self.backend.autocomplete("first <-> second", models.Book) self.assertUnsortedListEqual([r.title for r in results], []) + + def test_index_without_upsert(self): + # Test the add_items code path for Postgres 9.4, where upsert is not available + self.backend.reset_index() + + index = self.backend.get_index_for_model(models.Book) + index._enable_upsert = False + index.add_items(models.Book, models.Book.objects.all()) + + results = self.backend.search("JavaScript", models.Book) + self.assertUnsortedListEqual([r.title for r in results], [ + "JavaScript: The good parts", + "JavaScript: The Definitive Guide" + ])