17. Как использовать произвольные функции базы данных в кверисетах?¶
Django поставляется с такими функциями, как Lower
, Coalesce
и Max
, но он не может поддерживать все функции базы данных, особенно те, которые специфичны для базы данных.
Django предоставляет Func
, что позволяет использовать произвольные функции базы данных, даже если Django их не предоставляет.
Postgres имеет расширение fuzzystrmatch
, которое предоставляет несколько функций для определения сходства. Установите расширение в вашу БД postgres с помощью create extension fuzzystrmatch
.
Мы будем использовать функцию levenshtein
. Сначала создадим несколько объектов Hero.
Hero.objects.create(name="Zeus", description="A greek God", benevolence_factor=80, category_id=12, origin_id=1)
Hero.objects.create(name="ZeuX", description="A greek God", benevolence_factor=80, category_id=12, origin_id=1)
Hero.objects.create(name="Xeus", description="A greek God", benevolence_factor=80, category_id=12, origin_id=1)
Hero.objects.create(name="Poseidon", description="A greek God", benevolence_factor=80, category_id=12, origin_id=1)
Мы хотим найти Hero
объектов, которые имеют name
сходство с Зевсом. Вы можете сделать
from django.db.models import Func, F
Hero.objects.annotate(like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')"))
like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')")
принимала два аргумента, которые позволяли представить базу данных, а именно function
и template
. Если вам нужно повторно использовать функцию, вы можете определить класс следующим образом.
class LevenshteinLikeZeus(Func):
function='levenshtein'
template="%(function)s(%(expressions)s, 'Zeus')"
А затем используйте Hero.objects.annotate(like_zeus=LevenshteinLikeZeus(F("name")))
Затем вы можете фильтровать по этому аннотированному полю следующим образом.
In [16]: Hero.objects.annotate(
...: like_zeus=LevenshteinLikeZeus(F("name"))
...: ).filter(
...: like_zeus__lt=2
...: )
...:
Out[16]: <QuerySet [<Hero: Zeus>, <Hero: ZeuX>, <Hero: Xeus>]>