Alex Nelson
Alex Nelson

Reputation: 379

django rest framework order listview by serializer specific field

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.

Upvotes: 1

Views: 1203

Answers (1)

A. J. Parr
A. J. Parr

Reputation: 8026

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)

Upvotes: 1

Related Questions