Django 文本搜索与部分句子匹配更新到 django3

Django text search with partial sentence match update to 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 或者推荐类似搜索的任何解决方案吗?

所以我们很清楚,你的问题不是 Python 版本,而是 Django 版本。

您要找的应该是self.source_expressions[0]

但是,如果我今天重写这篇文章,我会先查看 raw search type (example) and pass my own query using the proximity operator <-> (example)。