tommueller
tommueller

Reputation: 2496

Pagination not using correct values when using order with two fields by in Django Rest Framework

I have a very simple ListAPIView:

class MyListView(ListAPIView):
    pagination_class = QueryParamPagination
    serializer_class = MyListSerializer
    queryset = MyObject.objects.all()

with a simple class to define the pagination:

class QueryParamPagination(PageNumberPagination):
    page_size = 2
    page_size_query_param = "page_size"
    max_page_size = 27

However in this scenario I will get a warning, because the result is not ordered: inconsistent results with an unordered object_list: <class 'models.MyObject'> MultilingualSoftDeleteQuerySet. Which is fine ...

Now changing the last line to

queryset = MyObject.objects.order_by('category', 'name').all()

gets rid of the warning, however now my pagination is not working anymore. Django now uses some super defaults, all values in QueryParamPaginationare ignored, but also my global settings

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 2,
}

Changing it again to

queryset = MyObject.objects.order_by('name').all()

works fine again. Is it not possible to use "double sorting" together with pagination?

Upvotes: 0

Views: 67

Answers (1)

KingRanTheMan
KingRanTheMan

Reputation: 740

I'm not totally sure why that is happening, but when DRF has given me issues with querysets in the past I've often found overriding the built-in get_queryset method can help, so you may wish to try this:

class MyListView(ListAPIView):
    pagination_class = QueryParamPagination
    serializer_class = MyListSerializer

    def get_queryset(self):
        qset = MyObject.objects.all().order_by('name')
        print(f"Qset: {qset}")
        return qset

Hopefully that works; if it doesn't, you may wish to try the below:

class MyListView(ListAPIView):
    pagination_class = QueryParamPagination
    serializer_class = MyListSerializer

    def get_queryset(self):
        orig_qset = MyObject.objects.all()
        qset = sorted(orig_qset, key=lambda item: item.name)
        print(f"Qset: {qset}")
        return qset

I've left the print statements in there so you can see whether there's anything in the ordering/sorting process that is causing the bug.

If this still doesn't work, my next thoughts would be (1) try over-riding the get_paginated_response method in a similar fashion, printing out the contents as you go, or (2) implementing your name-based ordering at the model level (inside the meta class of your MyObject model).

FWIW, when trying to debug any of the class-based objects in Django (Class-Based Views, Class-Based Forms, or Class-Based Django Rest Framework), I really recommend the 'Classy' pages. They are a phenomenally good tool for introspection. Links below:

Classy DRF

Classy Class-Based Views

Classy Forms

Upvotes: 0

Related Questions