Return only the most relevant result per object

This commit is contained in:
jeremystretch 2022-10-11 14:34:30 -04:00
parent 89b97642ad
commit 607312a456

View File

@ -4,6 +4,8 @@ from importlib import import_module
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db.models import F, Window
from django.db.models.functions import window
from django.db.models.signals import post_delete, post_save from django.db.models.signals import post_delete, post_save
from extras.models import CachedValue from extras.models import CachedValue
@ -152,7 +154,29 @@ class FilterSetSearchBackend(SearchBackend):
class CachedValueSearchBackend(SearchBackend): class CachedValueSearchBackend(SearchBackend):
def search(self, request, value, **kwargs): def search(self, request, value, **kwargs):
return CachedValue.objects.filter(value__icontains=value).prefetch_related('object')
# Define the search parameters
params = {
'value__icontains': value
}
# Construct the base queryset to retrieve matching results
queryset = CachedValue.objects.filter(**params).annotate(
# Annotate the rank of each result for its object according to its weight
row_number=Window(
expression=window.RowNumber(),
partition_by=[F('object_type'), F('object_id')],
order_by=[F('weight').asc()],
)
)
# Wrap the base query to return only the lowest-weight result for each object
# Hat-tip to https://blog.oyam.dev/django-filter-by-window-function/ for the solution
sql, params = queryset.query.sql_with_params()
return CachedValue.objects.prefetch_related('object').raw(
f"SELECT * FROM ({sql}) t WHERE row_number = 1",
params
)
@classmethod @classmethod
def cache(cls, instance, data): def cache(cls, instance, data):