I have a ListAPIView
that uses the DjangoFilterBackend
to filter rooms based on url parameters. The code below does this just fine.
Now, I would like to sort the results based on a score calculated from other attributes of the Room object, another url parameter, and possibly what we know about the user issuing the request. The function itself does not matter.
How can I sort the results after applying the filter I already have?
If I were to do the filtering myself, I suppose I could do the filtering, calculate the score and sort the results in the get_queryset
but I do not know how to do this after the filtering with django-filter
.
Example query
For example, I would do this query to filter by price lower than 100. The other_field
value would be used to compute the score for sorting:
http://localhost:8000/api/search/rooms?price=100&other_field=200
Code
class RoomFilter(filters.FilterSet):
price = filters.NumberFilter(name="price", lookup_expr='lte')
features = filters.ModelMultipleChoiceFilter(
name="features",
conjoined=True,
queryset=Features.objects.all()
)
class Meta:
model = Room
fields = ['price', 'features']
class RoomSearchView(generics.ListAPIView):
queryset = Room.objects.all()
serializer_class = RoomSearchSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = RoomFilter
Try to override list()
in your API as below,
class RoomSearchView(generics.ListAPIView):
queryset = Room.objects.all()
serializer_class = RoomSearchSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = RoomFilter
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
queryset = queryset.order_by('-id') # change is here >> sorted with reverse order of 'id'
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)