使用Django Rest Framework按降序忽略空值

njthzxwz  于 2023-02-10  发布在  Go
关注(0)|答案(4)|浏览(139)

我的网站使用Django,因此我决定使用Django Rest Framework来构建我的REST API。对于一个特定的模型,我想过滤一个文本字段(使用SearchFilter),过滤一些分类字段(定义了FilterSet的FilterBackend),并能够基于一些字段排序数据(使用OrderingFilter)。

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

我面临的问题是排序字段也包含空值。升序排序可以正常工作。但是降序排序(www.example.com/api/stats/?ordering =-appearance)会将空值推到顶部。
当使用降序时,如何忽略空值?可以执行排序的字段数量大约为20个。

pn9klfpd

pn9klfpd1#

这是一个稍微不同的解决方案--不是过滤空值,而是过滤器的替代品。OrderingFilter总是确保它们排序在最后:

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
r8uurelv

r8uurelv2#

您可以自定义自己的OrderingFilter

# Created by BaiJiFeiLong@gmail.com 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)
ttp71kqs

ttp71kqs3#

排序将排除空值,假设您的字段名为stats,您可以执行以下操作:

Stats.objects.exclude(stats__isnull=True).exclude(stats__exact='')
q8l4jmvw

q8l4jmvw4#

BaiJiFeiLong's solution几乎对我有用。经过一些调整,它最终达到了目的:

from django.db.models import F, OrderBy
from rest_framework.filters import OrderingFilter

class NullsLastOrderingFilter(OrderingFilter):

def get_ordering(self, request, queryset, view):
    values = super().get_ordering(request, queryset, view)
    return (OrderBy(F(value.lstrip("-")), descending=value.startswith("-"), nulls_last=True) for value in values)

相关问题