I am using Django for my website, and hence decided to use Django Rest Framework for building my REST APIs. For a particular model, i want to filter on a text field (using SearchFilter for that), filter on a few categorical fields (FilterBackend with a FilterSet defined) and be able to order data based on some fields (OrderingFilter for this).
class StatsAPI(generics.ListAPIView):
model = Stats
queryset = Stats.objects.all()
serializer_class = StatsSerializer
filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter, filters.SearchFilter)
filter_class = StatsFilter
pagination_class = StatsPagination
ordering_fields = ('__all__')
search_fields = ('display_name')
The issue i am facing is with my ordering fields as they also contain nulls. Ordering in ascending order works fine. However ordering in descending order (www.example.com/api/stats/?ordering=-appearance), pushes the null values to the top.
How do i ignore the null values when using descending order? The number of fields on which ordering can be performed are roughly 20 in number.
This is a slightly different solution -- rather than filtering null out, this replacement for filters.OrderingFilter just always makes sure they sort last:
class NullsAlwaysLastOrderingFilter(filters.OrderingFilter):
""" Use Django 1.11 nulls_last feature to force nulls to bottom in all orderings. """
def filter_queryset(self, request, queryset, view):
ordering = self.get_ordering(request, queryset, view)
if ordering:
f_ordering = []
for o in ordering:
if not o:
continue
if o[0] == '-':
f_ordering.append(F(o[1:]).desc(nulls_last=True))
else:
f_ordering.append(F(o).asc(nulls_last=True))
return queryset.order_by(*f_ordering)
return queryset
You can custom your own OrderingFilter
:
# Created by [email protected] at 2022/8/13
from django.db.models import F, OrderBy
from django_filters import rest_framework as filters
class MyOrderingFilter(filters.OrderingFilter):
def get_ordering_value(self, param):
value = super().get_ordering_value(param)
return OrderBy(F(value.lstrip("-")), descending=value.startswith("-"), nulls_last=True)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With