Django REST Framework查询集未排序

35 投票
5 回答
54334 浏览
提问于 2025-04-18 14:59

我在模型中使用了 Meta,并设置了 ordering = ['-published_date'],意思是我希望按照发布时间的倒序排列。

现在在视图中:

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

还有序列化器:

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

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

但是这个排序没有起作用,它显示的是升序(ASC),而我需要的是降序(DESC),根本没有影响到顺序。

我哪里做错了呢?

5 个回答

0

如果你是从谷歌搜索“如何对django-filters的查询集进行排序”而来的话,欢迎你!

在django-filters中,有一个叫做OrderingFilter的东西,你可以用它来添加排序功能。

文档中的示例代码是这样的:

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

这里的o是查询参数的名字。

所以如果你访问 www.domain.com/o=username,它会返回按用户名排序的查询集。如果你想要按降序排序,只需访问 www.domain.com/o=-username(注意在username前面有个-号)。

7

@Mirza Delic 的回答有效,但没有保持来自 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)

这个方法对我和其他人都有效,希望对你也有帮助。

30

在Django REST框架中,你可以使用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')
32

如果你的模型确实有一个排序方式,那么在列表视图中默认会显示出来。我建议你重写一下 get_queryset() 方法,并在这里调试返回的结果,或者直接在查询集中添加排序。

举个例子:

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

你有没有可能配置了一个过滤器,导致排序被覆盖了?可以试试把所有过滤器都关掉,看看会发生什么。我注意到你设置了 filter_fields 属性,所以假设你的设置里有类似这样的内容……

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

如果你把那部分注释掉,问题会解决吗?

24

解决办法是重写 filter_queryset 这个方法:

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

撰写回答