0

I am running django 2.1.7, DRF and using taggit. I am writing my own custom queryset to find tags that an object has. The url: example.com/api/tags=books,headphones,sleep

Should return JSON that has objects in order from contains most tags to contains at least one tag. Here is the gitgist

from django.db.models import Case, ExpressionWrapper, IntegerField, Q, Value, When

class SpecialSearch(ListAPIView):
    model = Object
    serializer_class = ObjectSerializer

    def get_queryset(self, rs, value):
        """
        Recipe search matching, best matching and kind of matching,
        by filtering against `tags` query parameter in the URL.
        """
        if value:
            tags = [tag.strip() for tag in value.split(',')]
            qs = Object.objects.filter(
                reduce(
                    lambda x, y: x | y, [Q(tags__icontains=tag) for tag in tags]))
            check_matches = map(
                lambda x: Case(
                    When(Q(tags__icontains=x), then=Value(1)),
                        default=Value(0)),
            tags)
            count_matches = reduce(lambda x, y: x + y, check_matches)
            qs = qs.annotate(
            matches=ExpressionWrapper(
                count_matches,
                output_field=IntegerField()))
            qs = qs.order_by('-matches')
        return qs

Currently, this code I submitted kind of works but is returning json that is ordered by the object ID and the API endpoint when submitting a new series of tags won't receive a new json dump from the API. I am totally lost right now. Any help would be absolutely appreciated.

4

1 回答 1

1

对于 OP 来说可能为时已晚,但如果有人看到这个,在 count_matches 周围添加 Sum() 可能会奏效:

from django.db.models import (Case, ExpressionWrapper, IntegerField, Q, Value, When, Sum)

class SpecialSearch(ListAPIView):
    model = Object
    serializer_class = ObjectSerializer

    def get_queryset(self, rs, value):
        """
        Recipe search matching, best matching and kind of matching,
        by filtering against `tags` query parameter in the URL.
        """
        if value:
            tags = [tag.strip() for tag in value.split(',')]
            qs = Object.objects.filter(
                reduce(
                    lambda x, y: x | y, [Q(tags__icontains=tag) for tag in tags]))
            check_matches = map(
                lambda x: Case(
                    When(Q(tags__icontains=x), then=Value(1)),
                        default=Value(0)),
            tags)
            count_matches = reduce(lambda x, y: x + y, check_matches)
            qs = qs.annotate(
            matches=ExpressionWrapper(
                Sum(count_matches),
                output_field=IntegerField()))
            qs = qs.order_by('-matches')
        return qs
于 2019-09-30T06:40:56.910 回答