Как использовать Substr с выражением F

Я пытаюсь создать набор Func классов, построенных на fuzzystrmatch расширении postgres.

Например, у меня есть эта обертка, которая принимает выражение Expression и поисковый запрос и возвращает расстояние Левенштейна:

class Levenshtein(Func):
    """This function calculates the Levenshtein distance between two strings:"""
    template = "%(function)s(%(expressions)s, '%(search_term)s')"
    function = "levenshtein"

    def __init__(self, expression, search_term, **extras):
        super(Levenshtein, self).__init__(
            expression,
            search_term=search_term,
            **extras
        ) 

Вызывается так, используя F Expression:

Author.objects.annotate(lev_dist=Levenshtein(F('name'),'JRR Tolkien').filter(lev_dist__lte=2)

Однако если поле 'name' здесь больше 255, то возникает ошибка:

И источник, и цель могут быть любой не нулевой строкой, максимум 255 символов.

Я могу усечь имя, когда аннотирую с помощью Substr:

Author.objects.annotate(clipped_name=Substr(F('name'),1,250))

Но я не могу понять, как разместить эту логику внутри func, который я размещаю внутри ExpressionWrapper и устанавливаю output_field согласно документации :

class Levenshtein(Func):
    """This function calculates the Levenshtein distance between two strings:"""
    template = "%(function)s(%(expressions)s, '%(search_term)s')"
    function = "levenshtein"

    def __init__(self, expression, search_term, **extras):
        super(Levenshtein, self).__init__(
            expression=ExpressionWrapper(Substr(expression, 1, 250), output_field=TextField()),
            search_term=search_term,
            **extras
        ) 

Хотя в документации это не очень понятно, просто путем экспериментов выяснилось, что ответ заключается в удалении дополнительного определения expression и передаче ExpressionWrapper непосредственно в качестве первого аргумента:

class Levenshtein(Func):
    """This function calculates the Levenshtein distance between two strings:"""
    template = "%(function)s(%(expressions)s, '%(search_term)s')"
    function = "levenshtein"

    def __init__(self, expression, search_term, **extras):
        super(Levenshtein, self).__init__(
            ExpressionWrapper(Substr(expression, 1, 250), output_field=TextField()),
            search_term=search_term,
            **extras
        ) 
Вернуться на верх