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
The filter() method is used to filter you search, and allows you to return only the rows that matches the search term.
Nope. Django filters operate at the database level, generating SQL. To filter based on Python properties, you have to load the object into Python to evaluate the property--and at that point, you've already done all the work to load it.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With