Django Rest Framework:如何对搜索/过滤查询进行排序/排序?

时间:2015-07-16 23:10:52

标签: python django rest django-rest-framework django-filter

我正在使用Django Rest Framework构建一个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

2 个答案:

答案 0 :(得分:3)

您希望按相关性对搜索结果进行排序,在您的情况下,grep -E -o "^[0-9]{23}[^0-9]+[0-9]+" MYFILE.TXT 应该是最佳结果,因为它与查询字完全匹配。

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

name: "Human"

此查询将查找包含" human"(忽略大小写)的所有记录,并按名称字段desc的长度对结果进行排序。 # 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") 将成为第一个显示的项目。

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

答案 1 :(得分:1)

我同意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具有更大相关性的结果而不是{{1} } 可能会找到。更多相关内容:Is there a way to filter a django queryset based on string similarity (a la python difflib)?

编辑:

虽然尝试提出一个为什么按字段值长度排序的例子是一个可怕的想法,但我实际上设法说服自己,与__icontains一起使用时可能不那么糟糕。我会留下这样的答案,因为它可能对某人有用或有趣。例如:

__icontains