37

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?

5
  • 1
    if your call Invoice.objects.all() from the shell does it show DESC ordering? Commented Jul 28, 2014 at 1:43
  • Yes it does.. that's weird. :/ Commented Jul 28, 2014 at 2:00
  • 1
    it must be somthing with DRF. what does your output look like? Commented Jul 28, 2014 at 2:09
  • I used rest client to see output, it just order it ASC. Can something be wrong with view, or serializer? Or is there any other way to do this? Commented Jul 28, 2014 at 2:36
  • 1
    you can override the get_queryset() method but, ive done this before just like you and its worked for me. Somehting else must be wrong. Commented Jul 28, 2014 at 2:47

5 Answers 5

34

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?

Sign up to request clarification or add additional context in comments.

4 Comments

It works when i comment this. Thanks, now can i make it work together?
The easy fix should be the .order_by listed above, but next step - why does using DjangoFilterBackend set an explicit ordering, instead of leaving the default? Is that a bug in django-filter or an integration issue in REST framework?
It still doesn't work when use queryset = Invoice.objects.all().order_by('-published_date') :(
Okay interesting, assuming that django-filter overrides the ordering then. Ticket is github.com/tomchristie/django-rest-framework/issues/1717
32

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')

3 Comments

For anyone thats banging their head on ordering via a query param manually in DRF, this solved a couple hour headache in minutes.Thank you!
If anyone's using django-filters and can't use another backend. See my answer below.
this explanation is pretty useful. Worth to mention that the import of filters.OrderingFilter must be from rest_framework instead of django_filters. This will may help to reduce hours of unnecessary headache, like the ones that I had
24

Solution is to override filter_queryset:

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

1 Comment

That's a lot of overhead for a simple feature. I wonder if this has changed in the last 4.5 years?
7

@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.

Comments

0

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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.