Repository: django/django
File: django/contrib/postgres/search.py (Python)

Code before:
    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = (*lhs_params, *rhs_params)
        return "%s @@ %s" % (lhs, rhs), params


class SearchVectorField(CheckPostgresInstalledMixin, Field):
    def db_type(self, connection):
        return "tsvector"


class SearchQueryField(CheckPostgresInstalledMixin, Field):
    def db_type(self, connection):
        return "tsquery"


class _Float4Field(Field):
    def db_type(self, connection):
        return "float4"


class SearchConfig(Expression):
    def __init__(self, config):
        super().__init__()
        if not hasattr(config, "resolve_expression"):
            config = Value(config)
        self.config = config

    @classmethod
    def from_parameter(cls, config):
        if config is None or isinstance(config, cls):
            return config
        return cls(config)

    def get_source_expressions(self):
        return [self.config]

    def set_source_expressions(self, exprs):
        (self.config,) = exprs

    def as_sql(self, compiler, connection):
        sql, params = compiler.compile(self.config)
        return "%s::regconfig" % sql, params


class SearchVectorCombinable:
    ADD = "||"

    def _combine(self, other, connector, reversed):
        if not isinstance(other, SearchVectorCombinable):

Review comment (security):
```suggestion

def normalize_spaces(val: str):
    """Converts multiple spaces to single and strips from both sides."""
    return re.sub(r"\s{2,}", " ", val.strip()) if val else None


def psql_escape(query: str):
    """Replace unsafe chars with space and convert multiple spaces to single."""
    return normalize_spaces(re.sub(r"['\0\[\]()|&:*!@<>\\]", " ", query))

```
It seems that you don't need to declare variable since you're not reusing them outside their functions.

Also, if you're not using the compiled regex more than one you don't need to compile them.
See https://docs.python.org/3/library/re.html#re.compile

Code after:

else:
    from psycopg2.extensions import adapt

    def quote_lexeme(value):
        adapter = adapt(psql_escape(value))
        adapter.encoding = "utf-8"
        return adapter.getquoted().decode()


spec_chars_re = _lazy_re_compile(r"['\0\[\]()|&:*!@<>\\]")
multiple_spaces_re = _lazy_re_compile(r"\s{2,}")


def normalize_spaces(val):
    """Convert multiple spaces to single and strip from both sides."""
    if not (val := val.strip()):
        return None
    return multiple_spaces_re.sub(" ", val)


def psql_escape(query):
    """Replace chars not fit for use in search queries with a single space."""
    query = spec_chars_re.sub(" ", query)
    return normalize_spaces(query)


class SearchVectorExact(Lookup):
    lookup_name = "exact"

    def process_rhs(self, qn, connection):
        if not isinstance(self.rhs, (SearchQuery, CombinedSearchQuery)):
            config = getattr(self.lhs, "config", None)
            self.rhs = SearchQuery(self.rhs, config=config)
        rhs, rhs_params = super().process_rhs(qn, connection)
        return rhs, rhs_params

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = (*lhs_params, *rhs_params)
        return "%s @@ %s" % (lhs, rhs), params


class SearchVectorField(CheckPostgresInstalledMixin, Field):
    def db_type(self, connection):
        return "tsvector"


class SearchQueryField(CheckPostgresInstalledMixin, Field):
    def db_type(self, connection):