Python Django Rest框架:如何对搜索/筛选查询进行排序?

Python Django Rest框架:如何对搜索/筛选查询进行排序?,python,django,rest,django-rest-framework,django-filter,Python,Django,Rest,Django Rest Framework,Django Filter,我正在用Django Rest框架构建一个API,我希望有一个允许用户通过查询进行搜索的特性。目前, http://127.0.0.1:8000/api/v1/species/?name=human收益率: { count: 3, next: null, previous: null, results: [ { id: 1, name: "Humanoid", characte

我正在用Django Rest框架构建一个API,我希望有一个允许用户通过查询进行搜索的特性。目前,
http://127.0.0.1:8000/api/v1/species/?name=human
收益率:

{
    count: 3,
    next: null,
    previous: null,
    results: [
        {
            id: 1,
            name: "Humanoid",
            characters: [
                {
                    id: 46,
                    name: "Doctor Princess"
                }
            ]
        },
        {
            id: 3,
            name: "Inhuman (overtime)",
            characters: [

            ]
        },
        {
            id: 4,
            name: "Human",
            characters: [
                {
                    id: 47,
                    name: "Abraham Lincoln"
                }
            ]
        }
    ]
}
它非常接近我想要的,但不完全在那里。我希望
results
中的第一个对象是
id
为4的对象,因为
name
字段与搜索查询最相关(?name=human)。(我真的不在乎其余部分是如何排序的。)似乎目前它正在按升序
id
对结果进行排序。有人知道处理这件事的好方法吗?谢谢

这是我的api文件夹的views.py

class SpeciesFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(name="name", lookup_type=("icontains"))
    class Meta:
        model = Species
        fields = ['name']

class SpeciesViewSet(viewsets.ModelViewSet):
    queryset = Species.objects.all()
    serializer_class = SpeciesSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    # search_fields = ('name',)
    filter_class = SpeciesFilter

您希望按相关性对搜索结果进行排序,在您的情况下,
名称:“Human”
应该是最佳结果,因为它与查询词完全匹配

如果只是为了解决问题,您可以使用原始sql查询来实现您的目标,如:

# NOT TESTED, sql expression may vary based on which database you are using
queryset = Species.objects.raw("select * from species where lower(name) like '%human%' order by char_length(name) desc limit 20")
此查询将查找所有包含“human”(忽略案例)的记录,并按名称字段desc的长度对结果进行排序。其中
name:“human”
将是第一个显示的项目



仅供参考,数据库查询通常不是做这类事情的最佳方法,你应该去检查项目,它可以帮助你在django项目上快速而简单地构建搜索引擎。

我同意django haystack上的@piglei,但我认为按字段值长度排序是个糟糕的主意,而且也没有必要为此编写SQL。更好的方法是:

 Species.objects.all().extra(select={'relevance': 'char_length(full_name)', order_by=['relevance'])  # PostgreSQl
仍然很糟糕,即使是作为一个快速解决方案。 如果您真的不想设置django haystack,一种稍微不那么糟糕的方法是使用python对结果进行排序:

from difflib import SequenceMatcher

species = Species.objects.all()

species = sorted(species,
                 lambda s: SequenceMatcher(None, needle.lower(), s.name.lower()).quick_ratio(),
                 reverse=True)
我没有测试这段代码,所以如果它不起作用请告诉我,如果您需要帮助将其集成到DRF中也请告诉我

这仍然很糟糕的原因是difflib的搜索算法与用于搜索数据库的算法不同,因此您可能永远不会得到使用difflib会比
\u icontains
可能找到的某些结果更具相关性的结果。更多信息请参见:

编辑: 当我试图举出一个例子来说明为什么按字段值长度排序是一个糟糕的想法时,我实际上说服了自己,当与
\uu icontains
一起使用时,它可能是不那么糟糕的想法。我会留下这样的答案,因为它可能对某人有用或有趣。例如:

needle = 'apple'
haystack = ['apple', 'apples', 'apple computers', 'apples are nice']  # Sorted by value length