Текстовый поиск Django с обновлением соответствия частичного предложения до django3

Я пытаюсь применить частичный поиск в Django postgres, точно так же, как описано здесь django -text-search-with-partial-sentence-match Я нашел там довольно хорошее решение

from psycopg2.extensions import adapt

from django.contrib.postgres.search import SearchQuery


class PrefixedPhraseQuery(SearchQuery):
"""
Alter the tsquery executed by SearchQuery
"""
    def as_sql(self, compiler, connection):
        # Or <-> available in Postgres 9.6
        value = adapt('%s:*' % ' & '.join(self.value.split()))

        if self.config:
            config_sql, config_params = compiler.compile(self.config)
            template = 'to_tsquery({}::regconfig, {})'\
                .format(config_sql, value)
            params = config_params

        else:
            template = 'to_tsquery({})'\
                .format(value)
            params = []

        if self.invert:
            template = '!!({})'.format(template)

        return template, params

Он отлично работает для Python 3.6, но не работает для 3.9. Разница в том, что в 3.6 SearchQuery наследуется от Value:

class SearchQuery(SearchQueryCombinable, Value):
    output_field = SearchQueryField()
    SEARCH_TYPES = {
        'plain': 'plainto_tsquery',
        'phrase': 'phraseto_tsquery',
        'raw': 'to_tsquery',
    }
    def __init__(self, value, output_field=None, *, config=None, invert=False, search_type='plain'):
        self.config = config
        self.invert = invert
        if search_type not in self.SEARCH_TYPES:
            raise ValueError("Unknown search_type argument '%s'." % search_type)
        self.search_type = search_type
        super().__init__(value, output_field=output_field)

а в Python 3.9 SearchQuery наследуется от Func:

class SearchQuery(SearchQueryCombinable, Func):
    output_field = SearchQueryField()
    SEARCH_TYPES = {
        'plain': 'plainto_tsquery',
        'phrase': 'phraseto_tsquery',
        'raw': 'to_tsquery',
        'websearch': 'websearch_to_tsquery',
    }

    def __init__(self, value, output_field=None, *, config=None, invert=False, search_type='plain'):
        self.function = self.SEARCH_TYPES.get(search_type)
        if self.function is None:
            raise ValueError("Unknown search_type argument '%s'." % search_type)
        if not hasattr(value, 'resolve_expression'):
            value = Value(value)
        expressions = (value,)
        self.config = SearchConfig.from_parameter(config)
        if self.config is not None:
            expressions = (self.config,) + expressions
        self.invert = invert
        super().__init__(*expressions, output_field=output_field)

В Func, в отличие от Value, нет self.value

class Func(SQLiteNumericMixin, Expression):
    """An SQL function call."""
    function = None
    template = '%(function)s(%(expressions)s)'
    arg_joiner = ', '
    arity = None  # The number of arguments the function accepts.

    def __init__(self, *expressions, output_field=None, **extra):
        if self.arity is not None and len(expressions) != self.arity:
            raise TypeError(
                "'%s' takes exactly %s %s (%s given)" % (
                    self.__class__.__name__,
                    self.arity,
                    "argument" if self.arity == 1 else "arguments",
                    len(expressions),
                )
            )
        super().__init__(output_field=output_field)
        self.source_expressions = self._parse_expressions(*expressions)
        self.extra = extra

и значение выглядит так

class Value(Expression):
    """Represent a wrapped value as a node within an expression."""
    def __init__(self, value, output_field=None):
        """
        Arguments:
         * value: the value this expression represents. The value will be
           added into the sql parameter list and properly quoted.

         * output_field: an instance of the model field type that this
           expression will return, such as IntegerField() or CharField().
        """
        super().__init__(output_field=output_field)
        self.value = value

Кто-нибудь помог мне настроить образец кода на python 3.9 или порекомендовал какое-либо решение для аналогичного поиска?


person alis01    schedule 29.01.2021    source источник


Ответы (1)


Итак, мы поняли, что ваша проблема здесь не в версии Python, а в версии Django.

То, что вы ищете, должно быть self.source_expressions[0].

Однако, если бы я переписывал это сегодня, я бы начал с просмотра raw тип поиска (пример) и передать мой собственный запрос с помощью оператора близости <-> (пример).

person Danielle Madeley    schedule 31.01.2021
comment
Спасибо за рекомендацию по необработанному типу поиска. Когда я пытаюсь заменить self.value на self.source_expressions[0], я получаю сообщение об ошибке value = adapt("%s:*" % " | ".join(self.source_expressions[0].split())) AttributeError: 'SearchConfig' object has no attribute 'split' . Я пробовал с str(self.source_expressions[0]), но потом получаю return self.cursor.execute(sql, params) django.db.utils.ProgrammingError: syntax error in tsquery: "<django.contrib.postgres.search.SearchConfig | object | at | 0x7f1c461bc7f0>:*" - person alis01; 01.02.2021
comment
извините за форматирование, но некоторые правила из comment-formatting, похоже, не действуют - person alis01; 01.02.2021
comment
Вы пытались использовать запрос raw с оператором <->? - person Danielle Madeley; 02.02.2021
comment
да. Это работает. Спасибо. В любом случае, мне было интересно узнать о предыдущем коде, так что у меня сработало self.source_expressions[1] - person alis01; 03.02.2021