From 1a28dc3887e8d66d5e3ff08cf7fb0a6212b873e5 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Fri, 20 Jul 2018 21:23:05 -0400 Subject: [PATCH] Fixed #29582 -- Fixed a crash when using SearchVector with non text-fields. The PostgreSQL concat() function handles nulls and non-text values better than the || operator. --- django/contrib/postgres/search.py | 9 +++------ tests/postgres_tests/test_search.py | 6 ++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/django/contrib/postgres/search.py b/django/contrib/postgres/search.py index a14d5102082..7bda2291a0c 100644 --- a/django/contrib/postgres/search.py +++ b/django/contrib/postgres/search.py @@ -1,6 +1,5 @@ from django.db.models import Field, FloatField from django.db.models.expressions import CombinedExpression, Func, Value -from django.db.models.functions import Coalesce from django.db.models.lookups import Lookup @@ -46,15 +45,13 @@ class SearchVectorCombinable: class SearchVector(SearchVectorCombinable, Func): function = 'to_tsvector' - arg_joiner = " || ' ' || " + arg_joiner = ", ' '," + template = '%(function)s(concat(%(expressions)s))' output_field = SearchVectorField() config = None def __init__(self, *expressions, **extra): super().__init__(*expressions, **extra) - self.source_expressions = [ - Coalesce(expression, Value('')) for expression in self.source_expressions - ] self.config = self.extra.get('config', self.config) weight = self.extra.get('weight') if weight is not None and not hasattr(weight, 'resolve_expression'): @@ -75,7 +72,7 @@ class SearchVector(SearchVectorCombinable, Func): if template is None: if self.config: config_sql, config_params = compiler.compile(self.config) - template = "%(function)s({}::regconfig, %(expressions)s)".format(config_sql.replace('%', '%%')) + template = "%(function)s({}::regconfig, concat(%(expressions)s))".format(config_sql.replace('%', '%%')) else: template = self.template sql, params = super().as_sql(compiler, connection, function=function, template=template) diff --git a/tests/postgres_tests/test_search.py b/tests/postgres_tests/test_search.py index 944690692a3..405de8cf0ea 100644 --- a/tests/postgres_tests/test_search.py +++ b/tests/postgres_tests/test_search.py @@ -155,6 +155,12 @@ class MultipleFieldsTest(GrailTestData, PostgreSQLTestCase): ).filter(search='bedemir') self.assertEqual(set(searched), {self.bedemir0, self.bedemir1, self.crowd, self.witch, self.duck}) + def test_search_with_non_text(self): + searched = Line.objects.annotate( + search=SearchVector('id'), + ).filter(search=str(self.crowd.id)) + self.assertSequenceEqual(searched, [self.crowd]) + def test_config_query_explicit(self): searched = Line.objects.annotate( search=SearchVector('scene__setting', 'dialogue', config='french'),