[Fixed]-Sort Django Rest Framework JSON Output


You can use SerializerMethodField and provide custom serialization logic there:

class EventSerializer(serializers.Serializer):
    events = serializers.SerializerMethodField(source="get_events")

    def get_events(self, events):
        event_list = {}
        return [event_list[e.type].add({e}) if event.type in event_list else event_list[event.type] = [] for event in events]


I had a model similar to the following:

class Book(models.Model):
    title = models.CharField(max_length=200)

class Author(models.Model):
    name = models.CharField(max_length=200)
    books = models.ManyToManyField(Book)

The JSON that was being generated for an Author looks like this:

  "name": "Sir Arthur C. Clarke",
  "books": [
      "title": "Rendezvous with Rama",
      "title": "Childhood's End",

In the JSON wanted the books to be sorted by title. Since the books are pulled into the queryset via a prefetch_related adding an order_by to the View’s queryset had no effect (generated SQL didn’t have a join to the Books table). The solution I came up with was to override the get method. In my version of the get method, I have the super class generate the Response and I modify it’s data (a Python dict) before returning it as shown below.

I’m not too worried about performance for two reasons:

  1. because of the prefetch_related the join is already being done in Python rather than in the database
  2. In my case the number of Books per Author is relatively small
class AuthorView(RetrieveUpdateAPIView):

    queryset = Author.objects.prefetch_related(
    serializer_class = AuthorSerializer

    def get(self, request, *args, **kwargs):
        response = super().get(request, *args, **kwargs)

        def key_func(book_json):
            return book_json.get('title', '')

        books = response.data.get('books', [])
        books = sorted(books, key=key_func)
        response.data['books'] = books

        return response

Leave a comment