如何在Django Rest中按搜索字符串匹配位置排序查询结果?
基于搜索字符串匹配位置排序Django Rest框架搜索结果
可以实现,核心思路是通过给查询集添加排序注解,区分「以搜索串开头」和「搜索串在中间」的结果,再按匹配位置排序。
实现步骤
- 筛选出包含搜索字符串的结果
- 给查询集添加两个注解:
starts_with:标记结果是否以搜索串开头(1为是,0为否),用于优先展示开头匹配的内容match_position:获取搜索串在字段中的起始位置,用于同类型结果内按匹配位置排序
- 按注解字段排序,先按
starts_with降序,再按match_position升序
代码示例
假设你的模型为MyModel,需要搜索的字段是name,在视图集中实现如下:
from django.db.models import Case, When, Value, IntegerField from django.db.models.functions import StrIndex from rest_framework import viewsets class MyModelViewSet(viewsets.ModelViewSet): serializer_class = MyModelSerializer queryset = MyModel.objects.all() def get_queryset(self): queryset = super().get_queryset() search_str = self.request.query_params.get('search', '') if search_str: # 筛选包含搜索字符串的记录 queryset = queryset.filter(name__icontains=search_str) # 添加排序注解 queryset = queryset.annotate( starts_with=Case( When(name__istartswith=search_str, then=Value(1)), default=Value(0), output_field=IntegerField() ), match_position=StrIndex('name', Value(search_str)) ) # 按优先级排序:开头匹配的在前,同优先级下匹配位置越靠前越前 queryset = queryset.order_by('-starts_with', 'match_position') return queryset
效果说明
针对你给出的示例:
- 原始匹配结果:
["another test", "test", "teeest"] - 排序后:
["test", "teeest", "another test"]test和teeest以te开头,starts_with=1,排在前面;两者的match_position都是1,顺序保持原查询集顺序(或可根据需求调整)another test的starts_with=0,match_position=8,排在最后
如果需要区分大小写搜索,将icontains改为contains,istartswith改为startswith即可。
内容的提问来源于stack exchange,提问作者sadat
相关产品推荐
相关产品推荐

