So I currently have a Drink serializer built using django rest framework. It has a field count_need that i obtain using a SerializerMethodField, which is not part of the Drink model. It also has a timestamp field that is part of the model. How can I order the ListAPI view by either timestamp or count_need based on parameters from a get request like /api/drink/?ordering=timestamp. Currently, i have ordering fields specified in the ListAPI view ordering_fields = ('count_need', 'timestamp', ) but it doesnt seem to be ordering the apiview on either query. I can order it by timestamp through the get_queryset method but this doesnt work for count_need because it is not part of the model.
Add a comment
|
1 Answer
You could try overriding the get_queryset method on your View and add an annotated field on your queryset for count_need. I think this would be preferable as it may be faster in SQL for large lists, and works with the built-in OrderingFilter of rest framework.
Example:
from django.db.models import Count
class MyView(APIView):
def get_queryset(self):
qs = self.queryset
qs = qs.annotate(count_need=Count('need'))
return qs
Recommended Reading:
https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#aggregations-and-other-queryset-clauses
The other option is to implement some custom ordering in Python instead of using the Django ORM. You could do this by overriding the list method on your ListAPI view.
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
serializer_data = serializer.data
sorted_serializer_data = sorted(serializer_data, key=lambda x: x['count_need'])
return self.get_paginated_response(sorted_serializer_data)
serializer = self.get_serializer(queryset, many=True)
serializer_data = serializer.data
sorted_serializer_data = sorted(serializer_data, key=lambda x: x['count_need'])
return Response(sorted_serializer_data)
1 Comment
Alex Nelson
Wow the second part of your answer is fantastic, I'll implement it in the morning and comment if it works! Thanks. It looks like it should as far as I can see