bsmith4
bsmith4

Reputation: 97

How to add an ArrayField to a SearchVector in Django?

I'm trying to use an ArrayField in a SearchVector but it is returning

django.db.utils.DataError: malformed array literal: ""
LINE 1: ... = to_tsvector(COALESCE("example_model"."example_arrayfield", ''))
                                                                      ^
DETAIL:  Array value must start with "{" or dimension information.

When I query for the ArrayField it returns a list e.g. ["a","b","c"] whereas in the database it is shown in curley brackets instead e.g.{a,b,c} Does anyone know how to get the SearchVector to accept an ArrayField as just a plain list? OR somehow convert the normal list to curley brackets?

Here is the code that starts this:

ExampleModel.objects.update(search_document=SearchVector("example_ArrayField"))

Upvotes: 2

Views: 1578

Answers (1)

Thibault J
Thibault J

Reputation: 4456

I know it's been a year, but I stumbled on this question via Google and could not find anybody with an acceptable solution for this exact problem, so here's the code I'm using.

from django.db.models import F, Func, Value
from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.search import SearchVector, SearchVectorField


class SearchableStuff(models.Model):
    name = models.CharField(
        _('Name'),
        max_length=256,
        null=False, blank=False)
    tags = ArrayField(
        models.CharField(max_length=50, blank=True),
        verbose_name=_('Tags'),
        default=list,
        size=16,
        blank=True)
    search_vector = SearchVectorField(
        _('Search vector'),
        null=True)

    def save(self, *args, **kwargs):
        self.search_vector = \
            SearchVector('name', weight='A', config='french') + \
            SearchVector(
                Func(F('tags'), Value(' '), function='array_to_string'),
                weight='A',
                config='french')
        return super().save(*args, **kwargs)

--Edit-- a few hours after posting this solution, I realized that it does only work when updating a record, but not inserting it. Here's a better solution.

def save(self, *args, **kwargs):
    # Note: we use `SearchVector(Value(self.field))` instead of
    # `SearchVector('field')` because the latter only works for updates,
    # not when inserting new records.
    self.search_vector = \
        SearchVector(Value(self.name), weight='A', config='french') + \
        SearchVector(
            Value(' '.join(self.tags)),
            weight='A',
            config='french')
    return super().save(*args, **kwargs)

Upvotes: 7

Related Questions