简体   繁体   English

使用django-filter进行不区分大小写的排序

[英]Do case-insensitive ordering with django-filter

Is it possible to do case-insensitive ordering by first_name with Django-rest-framework . 是否可以通过first_nameDjango-rest-framework case-insensitive排序。

Here is the code: 这是代码:

import django_filter

class PersonFilter(django_filters.FilterSet):
    class Meta:
        model = Person
        fields = ('first_name_lower',)
        order_by = ('first_name_lower',)

class PersonViewSet(BaseModelViewSet):
    queryset = Person.objects.all()
    permission_classes = (permissions.IsAuthenticated,)
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = PersonFilter

Is there an easy way to do case-insensitive ordering with django-filter ? 是否有一种简单的方法可以使用django-filter case-insensitive排序?

Here django-filter has docs for case-insensitive search , but nothing for ordering . 这里 django-filter有不区分大小写搜索的文档,但没有用于排序

In the Django docs, the code is somewhat obtuse for this, which makes me wonder if it exists for django-filter or not. 在Django文档中,代码对此有点迟钝,这让我想知道是否存在django-filter Here's the Django docs code snippet on how to do it with the Django ORM: 这里是关于如何使用Django ORM的Django文档代码片段:

>>> from django.db.models.functions import Lower
>>> MyModel.objects.order_by(Lower('myfield'))

You might want to subclass the OrderingFilter and use it as your filter_backend so that you can reuse the code. 您可能希望将OrderingFilter子类化并将其用作filter_backend以便您可以重用代码。

from rest_framework.filters import OrderingFilter
from django.db.models.functions import Lower

class CaseInsensitiveOrderingFilter(OrderingFilter):
    def filter_queryset(self, request, queryset, view):
        ordering = self.get_ordering(request, queryset, view)

        if ordering is not None:
            if ordering.startswith('-'):
                queryset = queryset.order_by(Lower(ordering[1:])).reverse()
            else:
                queryset = queryset.order_by(Lower(ordering))
        return queryset


class PersonViewSet(ModelViewSet):
    queryset = Person.objects.all()
    serializer_class = MySerializer
    permission_classes = (permissions.IsAuthenticated,)
    filter_backends = (CaseInsensitiveOrderingFilter,)

The case-insensitive search can be done by overriding the get_queryset method on the ModelViewSet class. case-insensitive搜索可以通过重写来完成get_queryset的方法ModelViewSet类。

It works for descending and ascending case-insensitive ordering. 它适用于降序升序 case-insensitive顺序。

# Example URL's
'/api/people/?ordering=-first_name'
'/api/people/?ordering=first_name'

Here's the code: 这是代码:

class PersonViewSet(ModelViewSet):
    queryset = Person.objects.all()
    serializer_class = MySerializer
    permission_classes = (permissions.IsAuthenticated,)

    def get_queryset(self):
        queryset = self.queryset
        ordering = self.request.query_params.get('ordering', None)
        if ordering is not None:
            from django.db.models.functions import Lower
            if ordering.startswith('-'):
                queryset = queryset.order_by(Lower(ordering[1:])).reverse()
            else:
                queryset = queryset.order_by(Lower(ordering))
        return queryset

from django.db.models.functions import Lower only works for Ascending, so basically call .reverse() on it if you need to go Descending. from django.db.models.functions import Lower只适用于升序,所以如果需要降序,基本上可以调用.reverse()

You can replace the filter function of OrderingFilter , and set the ordering params in Lower : 您可以替换OrderingFilterfilter函数,并在Lower设置排序参数:

class CaseInsensitiveOrderingFilter(django_filters.OrderingFilter):
    def filter(self, qs, value):
        if value in django_filters.constants.EMPTY_VALUES:
            return qs

        ordering = [Lower(self.get_ordering_value(param)) for param in value]
        return qs.order_by(*ordering)

use the ordering and ordering_fields arguments in your django-rest list view - http://www.django-rest-framework.org/api-guide/filtering/#specifying-a-default-ordering 使用django-rest列表视图中的ordering和ordering_fields参数 - http://www.django-rest-framework.org/api-guide/filtering/#specifying-a-default-ordering

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = ('username', 'email')
    ordering = ('username',)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM