如何解决如何在Django中优先搜索?
我在mysql数据库中使用djangorestframework。 我有一个视图,该视图根据搜索查询参数返回一个列表。 我正在使用rest_frameworks.filters SearchFilter进行基于搜索的过滤。 这是我的观点:
from rest_framework import filters
from rest_framework.generics import ListAPIView
...
class FooListView(ListAPIView):
serializer_class = SymbolSerializer
queryset = Symbol.objects.all()
filter_backends = [filters.SearchFilter]
search_fields = ['field_A','field_B','field_C']
要调用的示例网址是:
http://localhost:8000/symbols/symbols/?search=bird
现在一切正常,但是我需要一个过滤器功能。SearchFilter不支持。 我希望我的搜索按search_fields的优先级排序。
例如,这里有两个记录:
foo1:{“ field_A”:“ any”,“ field_B”:“ many”,“ field_C”:“ bar”,“ id”:3}
foo2:{“ field_A”:“许多”,“ field_B”:“任何”,“ field_C”:“ bar”,“ id”:4}
现在,当我使用search = 'many'参数进行搜索时,我希望视图向我返回一个列表,其中foo2记录高于foo1(例如[foo2,foo1]),因为我希望搜索的优先级为field_A成绩,但它只返回一个按ID([foo1,foo2])排序的列表。
有帮助吗?
解决方法
我刚偶然遇到了同样的问题。
我的解决方案是使用this response的启发来稍微调整DRF filters.SearchFilter
的搜索逻辑,最后得到以下定制过滤器类:
class PriorizedSearchFilter(filters.SearchFilter):
def filter_queryset(self,request,queryset,view):
"""Override to return priorized results."""
# Copy paste from DRF
search_fields = getattr(view,'search_fields',None)
search_terms = self.get_search_terms(request)
if not search_fields or not search_terms:
return queryset
orm_lookups = [
self.construct_search(six.text_type(search_field))
for search_field in search_fields
]
base = queryset
conditions = []
# Will contain a queryset for each search term
querysets = list()
for search_term in search_terms:
queries = [
models.Q(**{orm_lookup: search_term})
for orm_lookup in orm_lookups
]
# Conditions for annotated priority value. Priority == inverse of the search field's index.
# Example:
# search_fields = ['field_A','field_B','field_C']
# Priorities are field_A = 2,field_B = 1,field_C = 0
when_conditions = [models.When(queries[i],then=models.Value(len(queries) - i - 1)) for i in range(len(queries))]
# Generate queryset result for this search term,with annotated priority
querysets.append(
queryset.filter(reduce(operator.or_,queries))
.annotate(priority=models.Case(
*when_conditions,output_field=models.IntegerField(),default=models.Value(-1)) # Lowest possible priority
)
)
# Intersect all querysets and order by highest priority
queryset = reduce(operator.and_,querysets).order_by('-priority')
# Copy paste from DRF
if self.must_call_distinct(queryset,search_fields):
# Filtering against a many-to-many field requires us to
# call queryset.distinct() in order to avoid duplicate items
# in the resulting queryset.
# We try to avoid this if possible,for performance reasons.
queryset = distinct(queryset,base)
return queryset
使用filter_backends = [PrioritizedSearchFilter]
,您已设置好。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。