MattBroach / DjangoRestMultipleModels

View (and mixin) for serializing multiple models or querysets in Django Rest Framework
MIT License
549 stars 67 forks source link

Sorting by a date field #54

Closed oilyquack closed 3 years ago

oilyquack commented 3 years ago

I have a viewset that returns 2 models in a querylist, both with a booking_date Date field.

class MyAPIView(FlatMultipleModelAPIView):
    sorting_fields = ['-booking_date']

    querylist = [
        {'queryset': ModelA.objects.all(), 'serializer_class': ModelASerializer},
        {'queryset': ModelB.objects.all(), 'serializer_class': ModelBSerializer},
    ]

I want the resulting list to be ordered by this date field with newest at the top and going in descending order, like this:

[
   {
      "type": "ModelA",
      "booking_date": "25/12/2021"
    },
    {
      "type": "ModelB",
      "booking_date": "23/12/2021"
    },
    {
      "type": "ModelA",
      "booking_date": "21/12/2021"
    }
]

Is such a feature achievable using DjangoRestMultipleModels where I can order my querylist by a date field? Ordinarily I would leverage Django's .order_by("-booking_date)" to achieve this for a single model viewset. Using sorting_fields seems to only return my querylist alphabetically.

MattBroach commented 3 years ago

Hey @oilyquack -- the issue here is that because the FlatMultipleModelAPIView is combining from multiple sources, the sorting can only happen after serialization. At that point, you have strings, and so it's going to sort those strings via alphabetical order.

Your best bet for handling the sorting is to override the sort_results function on your view. Here's an example of how this might work (code is untested, but should get you started on the right path):

def sort_date_strings(date_string):
    day, month, year = date_string.split('/')
    return int(year), int(month), int(day)

class MyAPIView(FlatMultipleModelAPIView):
    sorting_fields = ['-booking_date']

    querylist = [
        {'queryset': ModelA.objects.all(), 'serializer_class': ModelASerializer},
        {'queryset': ModelB.objects.all(), 'serializer_class': ModelBSerializer},
    ]

    def sort_results(self, results):
          return sorted(results, key=sort_date_strings, reverse=True)

Closing for now, but feel free to reopen if you have more issues