Kaydet (Commit) 1a28dc38 authored tarafından Simon Charette's avatar Simon Charette

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.
üst 71a739f3
from django.db.models import Field, FloatField from django.db.models import Field, FloatField
from django.db.models.expressions import CombinedExpression, Func, Value from django.db.models.expressions import CombinedExpression, Func, Value
from django.db.models.functions import Coalesce
from django.db.models.lookups import Lookup from django.db.models.lookups import Lookup
...@@ -46,15 +45,13 @@ class SearchVectorCombinable: ...@@ -46,15 +45,13 @@ class SearchVectorCombinable:
class SearchVector(SearchVectorCombinable, Func): class SearchVector(SearchVectorCombinable, Func):
function = 'to_tsvector' function = 'to_tsvector'
arg_joiner = " || ' ' || " arg_joiner = ", ' ',"
template = '%(function)s(concat(%(expressions)s))'
output_field = SearchVectorField() output_field = SearchVectorField()
config = None config = None
def __init__(self, *expressions, **extra): def __init__(self, *expressions, **extra):
super().__init__(*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) self.config = self.extra.get('config', self.config)
weight = self.extra.get('weight') weight = self.extra.get('weight')
if weight is not None and not hasattr(weight, 'resolve_expression'): if weight is not None and not hasattr(weight, 'resolve_expression'):
...@@ -75,7 +72,7 @@ class SearchVector(SearchVectorCombinable, Func): ...@@ -75,7 +72,7 @@ class SearchVector(SearchVectorCombinable, Func):
if template is None: if template is None:
if self.config: if self.config:
config_sql, config_params = compiler.compile(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: else:
template = self.template template = self.template
sql, params = super().as_sql(compiler, connection, function=function, template=template) sql, params = super().as_sql(compiler, connection, function=function, template=template)
......
...@@ -155,6 +155,12 @@ class MultipleFieldsTest(GrailTestData, PostgreSQLTestCase): ...@@ -155,6 +155,12 @@ class MultipleFieldsTest(GrailTestData, PostgreSQLTestCase):
).filter(search='bedemir') ).filter(search='bedemir')
self.assertEqual(set(searched), {self.bedemir0, self.bedemir1, self.crowd, self.witch, self.duck}) 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): def test_config_query_explicit(self):
searched = Line.objects.annotate( searched = Line.objects.annotate(
search=SearchVector('scene__setting', 'dialogue', config='french'), search=SearchVector('scene__setting', 'dialogue', config='french'),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment