Nathan
Nathan

Reputation: 301

Django custom ordering in url queries

Update Two

So unfortunately, @Reza Torkaman Ahmadi's idea didn't work out in the end. This is because our program has a filtering function that relies on get_queryset, and overriding the get_queryset method in our views was messing up that function.

So, my partner and I discussed it, and here's what he came up with.

class OrderbyFilter(filters.OrderingFilter): def get_ordering(self, request, queryset, view): """ Ordering is set by a comma delimited ?$orderby=... query parameter. Extends the OrderingFilter of the django rest framework to redefine ordering parameters to "asc" and "desc". """ params = request.query_params.get(self.ordering_param) if params: field_queries = [param.strip() for param in params.split(',')] fields = [] for field_query in field_queries: field_query = field_query.split() if len(field_query) <= 2: while "asc" in field_query: field_query.remove("asc") for i, field in enumerate(field_query): if field == "desc": field_query[i-1] = "-" + field_query[i-1] while "desc" in field_query: field_query.remove("desc") fields.append(field_query[0]) else: fields.append([param.strip() for param in params.split(',')]) ordering = self.remove_invalid_fields(queryset, fields, view, request) if ordering: return ordering return self.get_default_ordering(view)

Basically, this function over-rides Django REST's source code, specifically the get_ordering function in the OrderingFilter. What it does is, if 'asc' is in the query after the field, it removes it and treats it like normal (for normal ascension ordering)

Otherwise if 'desc' is there, it removed the 'desc', and applies a hyphen.

Update Answered. Applied @Reza Torkaman Ahmadi idea and it works great after modifying it to fit my needs. Thanks mate!

Currently, in Django API rest framework, if a user wants to see a list of something in ascending or descending order, they have to do the following:

'Datastream&order_by=-name' shows names in descending order 'Datastream&order_by=name' shows names in ascending order.

I want to make a custom query where typing in 'Datastream&order_by=asc name' will order the names by ascending order, and 'desc name' will do so in descending order.

I've looked at some of the source code for the REST framework, but I may be looking in the wrong area. Getting stumped on what I should do. Any ideas?

Upvotes: 6

Views: 5421

Answers (2)

Kau&#234; Oliveira
Kau&#234; Oliveira

Reputation: 179

Django Rest Framework's standard way:

from rest_framework.filters import OrderingFilter

Then on your APIView or ViewSet

filter_backends = (OrderingFilter,)
ordering_fields = ['field_name']

query parameter is ordering and supports reverse ordering as well.

GET https://example.com/?ordering=-field_name

Upvotes: 5

Reza Torkaman Ahmadi
Reza Torkaman Ahmadi

Reputation: 3038

You can do it in your own way. like this:

class DatastreamViewSet(ModelViewSet):

    def get_queryset(self):
        queryset = super(DatastreamViewSet, self).get_queryset()

        order_by = self.request.query_params.get('order_by', '')
        if order_by:
            order_by_name = order_by.split(' ')[1]
            order_by_sign = order_by.split(' ')[0]
            order_by_sign = '' if order_by_sign == 'asc' else '-'
            queryset = queryset.order_by(order_by_sign + order_by_name)

        return queryset

this will look for query parameter order_by if is supplied then will split it by space, the first one will indicate to use + or - sign on order_by filter, and the second will be the name of it. so put it all together and create a text, pass it to order_by and your good to go.

for example:

?order_by=asc name

will be like this in django =>

return queryset.order_by('name')

Upvotes: 8

Related Questions