简体   繁体   English

如何根据 django-rest-framework 中的最佳匹配对查询集进行排序?

[英]How to order queryset based on best match in django-rest-framework?

I am trying to order results of a query with parameters by number of matches .我正在尝试按匹配数对带有参数的查询结果进行排序

For example, let's say we have a Model:例如,假设我们有一个模型:

class Template(models.Model):
    headline = CharField(max_length=300)
    text = TextField()
    image_text = TextField(max_length=500, blank=True, null=True)
    tags = TaggableManager(through=TaggedItem)
    ...

With a Serializer:使用序列化程序:

class TemplateSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Template
        fields = (...)

And a ViewSet:和一个视图集:

class TemplateViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows Templates to be viewed or edited.
    """
    queryset = Template.objects.all()
    serializer_class = TemplateSerializer

    def get_queryset(self):
        queryset = Template.objects.all()

        tags = self.request.query_params.getlist('tags', None)
        search_text = self.request.query_params.getlist('search_text', None)

        if tags is not None:
            queries = [Q(groost_tags__name__iexact=tag) for tag in tags]
            query = queries.pop()
            for item in queries:
                query |= item

            queryset = queryset.filter(query).distinct()

        if search_tags is not None:
            queries = [Q(image_text__icontains=string) |
                       Q(text__icontains=string) |
                       Q(headline__icontains=string) for string in search_tags]
            query = queries.pop()
            for item in queries:
                query |= item

            queryset = queryset.filter(query).distinct()

What I need to do is count every match the filter finds and then order the queryset by that number of matches for each template.我需要做的是计算过滤器找到的每个匹配项,然后按每个模板的匹配项数对查询集进行排序。 For example:例如:

I want to find all the templates that have "hello" and "world" strings in their text, image_text or headline.我想找到所有在文本、图像文本或标题中包含“hello”“world”字符串的模板。 So I set the query parameter "search_text" to hello,world .所以我将查询参数“search_text”设置hello,world Template with headline=" World " and text=" Hello , everyone."带有标题 =“世界文本 =“大家,大家”的模板 would have 2 matches .将有2 场比赛 Another one with headline=" Hello " would have 1 match .另一个标题为“你好”的将有1 个匹配项 The template with 2 matches would be the first in the queryset.具有 2 个匹配项的模板将是查询集中的第一个模板。 The same behaviour should work for tags and tags with search_text combined .相同的行为应该适用于带有search_text组合的标签标签

I tried to calculate these numbers right in the ViewSet and then return a sorted(queryset, key=attrgetter('matches')) but encountered several issues with the DRF, like Template has no attribute 'matches'.我试图在 ViewSet 中计算这些数字,然后返回一个sorted(queryset, key=attrgetter('matches'))但遇到了 DRF 的几个问题,比如Template 没有属性“matches”。 Or 404 when directly accessing a Template instance through API.或者通过 API 直接访问 Template 实例时出现 404。

Any ideas?有任何想法吗?

Give a try to annotation where each matching pair returns 1 or 0 that are summarized into rank:尝试annotation ,其中每个匹配对返回 1 或 0,并汇总为排名:

from django.db.models import Avg, Case, F, FloatField, Value, When

Template.objects.annotate(
    k1=Case(
        When(image_text__icontains=string, then=Value(1.0)),
        default=Value(0.0),
        output_field=FloatField(),
    ),
    k2=Case(
        When(text__icontains=string, then=Value(1.0)),
        default=Value(0.0),
        output_field=FloatField(),
    ),
    k3=Case(
        When(headline__icontains=string, then=Value(1.0)),
        default=Value(0.0),
        output_field=FloatField(),
    ),
    rank=F("k1") + F("k2") + F("k3"),
).order_by("-rank")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM