django rest framework queryset doesn't order

Question:

i use model with Meta ordering = ['-published_date']

Now in view:

class InvoiceViewSet(viewsets.ModelViewSet):
    queryset = Invoice.objects.all()
    serializer_class = InvoiceSerializer
    filter_fields = ('table',)

And serializer:

class InvoiceSerializer(serializers.ModelSerializer):
    items = ItemSerializer(many=True, allow_add_remove=True)

    class Meta:
        model = Invoice
        fields = ('id',  'items', 'table', 'published_date')

But this ordering doesn’t work, it shows me ordering ASC, and i need DESC, it doesn’t affect order at all.

What am i doing wrong?

Asked By: Mirza Delic

||

Answers:

If your model does have an ordering it really will be reflected in the list view by default. I’d suggest overriding get_queryset() and debugging the return result there, or else explicitly adding the ordering to the queryset.

For example:

queryset = Invoice.objects.all().order_by('-published_date')

Wondering if it’s possible you’ve configured a filter that’s overriding the ordering. Worth testing what happens if you turn all filters off. I see you have the filter_fields attribute set, so assuming you’ve got something like this in your settings…

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)
}

If you comment that out does that fix things?

Answered By: Tom Christie

Solution is to override filter_queryset:

def filter_queryset(self, queryset):
    queryset = super(InvoiceViewSet, self).filter_queryset(queryset)
    return queryset.order_by('-published_date')
Answered By: Mirza Delic

@Mirza Delic answer works but does not keep the ordering comming from request.QUERY_PARAMS.

class YOUR_VIEW_SET(viewsets.ModelViewSet):
    #your code here
    ordering_filter = OrderingFilter()

    def filter_queryset(self, queryset):
        queryset = super(YOUR_VIEW_SET, self).filter_queryset(queryset)
        return self.ordering_filter.filter_queryset(self.request, queryset, self)

This works for me and for other people I hope.

Answered By: EdgarT

For Django REST Framework you can use OrderingFilter.

from django_filters import DjangoFilterBackend
from rest_framework import viewsets, filters


class InvoiceViewSet(viewsets.ModelViewSet):
    queryset = Invoice.objects.all()
    serializer_class = InvoiceSerializer

    filter_backends = (DjangoFilterBackend, filters.OrderingFilter)

    # Explicitly specify which fields the API may be ordered against
    ordering_fields = ('items', 'table', 'published_date')

    # This will be used as the default ordering
    ordering = ('-published_date')
Answered By: shiva reddy

If anyone’s coming here from google for ‘How to order django-filters queryset’.

There’s OrderingFilter in django-filters, which you can use to add the order_by functionality.
The example code from the docs looks like this :

class UserFilter(FilterSet):
account = CharFilter(field_name='username')
status = NumberFilter(field_name='status')

o = OrderingFilter(
    # tuple-mapping retains order
    fields=(
        ('username', 'account'),
        ('first_name', 'first_name'),
        ('last_name', 'last_name'),
    ),

    # labels do not need to retain order
    field_labels={
        'username': 'User account',
    }
)

class Meta:
    model = User
    fields = ['first_name', 'last_name']

Where o is the name of the query param.
So if you hit www.domain.com/o=username. It will return the queryset ordered by username. If you want to order_by in descending order. Just do www.domain.com/o=-username (notice the – before username).

Answered By: Mazhar Ali