DRF框架基本组件之过滤,搜索,排序

Filtering

“ 由Django Manager提供的根QuerySet描述了数据库表中的所有对象。可是通常你需要的只是选择完整对象中的一个子集而已。

—— Django文档 ”

REST framework列表视图的默认行为是返回一个model的全部queryset。通常你却想要你的API来限制queryset返回的数据。

最简单的过滤任意GenericAPIView子视图queryset的方法就是重写它的.get_queryset()方法。

重写这个方法允许你使用很多不同的方式来定制视图返回的queryset。

Filtering against the current user(根据当前用户进行过滤)

您可能想要过滤queryset,以确保只返回与发出请求的当前已验证用户相关的结果。

你可以通过基于request.user的值进行过滤来实现。

比如:

from myapp.models import Purchase
from myapp.serializers import PurchaseSerializer
from rest_framework import generics

class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        This view should return a list of all the purchases
        for the currently authenticated user.
        """
        user = self.request.user
        return Purchase.objects.filter(purchaser=user)

Filtering against the URL(根据URL进行过滤)

另一种过滤方式可能包括基于URL的某些部分来限制queryset。

例如,如果你的URL配置包含一个参数如下:

url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),

你就可以写一个view,返回基于URL中的username参数进行过滤的结果。

class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        This view should return a list of all the purchases for
        the user as determined by the username portion of the URL.
        """
        username = self.kwargs['username']
        return Purchase.objects.filter(purchaser__username=username)

Filtering against query parameters(根据查询参数进行过滤)

过滤初始查询集的最后一个示例是基于url中的查询参数确定初始查询集。

我们可以通过重写.get_queryset()方法来处理像http://example.com/api/purchases?username=denvercoder9这样的网址,并且只有在URL中包含username参数时,才过滤queryset:

class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        Optionally restricts the returned purchases to a given user,
        by filtering against a `username` query parameter in the URL.
        """
        queryset = Purchase.objects.all()
        username = self.request.query_params.get('username', None)
        if username is not None:
            queryset = queryset.filter(purchaser__username=username)
        return queryset

Generic Filtering(通用过滤)

除了能够重写默认的queryset,REST框架还包括对通用过滤后端的支持,允许你轻松构建复杂的检索器和过滤器。

通用过滤器也可以在browsable API和admin API中显示为HTML控件。

Setting filter backends(设置通用过滤后端)

默认过滤器后端可以在全局设置中使用DEFAULT_FILTER_BACKENDS来配置。例如。

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

你还可以使用基于GenericAPIView类的视图在每个view或每个viewset基础上设置过滤器后端。

import django_filters.rest_framework
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)

DjangoFilterBackend(Django过滤后端)

django-filter库包含一个为REST framework提供高度可定制字段过滤的DjangoFilterBackend类。

要使用DjangoFilterBackend,首先要先安装django-filter

pip install django-filter

现在,你需要将filter backend 添加到你django project的settings中:
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

或者你也可以将filter backend添加到一个单独的view或viewSet中:

from django_filters.rest_framework import DjangoFilterBackend

class UserListView(generics.ListAPIView):
    ...
    filter_backends = (DjangoFilterBackend,)

如果你正在使用 browsable API或 admin API,你还需要安装django-crispy-forms,通过使用Bootstarp3渲染来提高filter form在浏览器中的展示效果。

pip install django-crispy-forms
安装完成后,将crispy-forms添加到你Django project的INSTALLED_APPS中,browsable API将为DjangoFilterBackend提供一个像下面这样的filter control:

Specifying filter fields(指定筛选字段)

如果你的需求都是些简单相等类型的筛选,那么你可以在你的view或viewSet里面设置一个filter_fields属性,列出所有你想依靠筛选的字段集合。

class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('category', 'in_stock')

这将为你列出来的字段自动创建一个filterSet,允许你想下面这样请求筛选结果:

http://example.com/api/products?category=clothing&in_stock=True

Specifying a FilterSet(指定FilterSet)

对于更高级的过滤要求,你可以指定在view中应该使用的FilterSet类。例如:

import django_filters
from myapp.models import Product
from myapp.serializers import ProductSerializer
from rest_framework import generics

class ProductFilter(django_filters.rest_framework.FilterSet):
    min_price = django_filters.NumberFilter(name="price", lookup_expr='gte')
    max_price = django_filters.NumberFilter(name="price", lookup_expr='lte')
    class Meta:
        model = Product
        fields = ['category', 'in_stock', 'min_price', 'max_price']

class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
    filter_class = ProductFilter

这将允许你向下面一样发出请求,如:

http://example.com/api/products?category=clothing&max_price=10.00
你也可以使用django-filter跨越关系,让我们假设每个产品都有Manufacturer模型的外键,所以我们创建过滤器使用Manufacturer名称过滤。例如:
import django_filters
from myapp.models import Product
from myapp.serializers import ProductSerializer
from rest_framework import generics

class ProductFilter(django_filters.rest_framework.FilterSet):
    class Meta:
        model = Product
        fields = ['category', 'in_stock', 'manufacturer__name']

这使我们能够进行如下查询:

http://example.com/api/products?manufacturer__name=foo

SearchFilter(搜索过滤)

SearchFilter类支持基于简单单查询参数的搜索,并且基于Django admin的搜索功能。

在使用时, browsable API将包括一个SearchFilter控件:

search-filter.png

仅当view中设置了search_fields属性时,才应用SearchFilter类。search_fields属性应该是model中文本类型字段的名称列表,例如CharFieldTextField
class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (filters.SearchFilter,)
    search_fields = ('username', 'email')

这将允许客户端通过进行以下查询来过滤列表中的项目:

http://example.com/api/users?search=russell

你还可以在查找API中使用双下划线符号对ForeignKey或ManyToManyField执行相关查找:

search_fields = ('username', 'email', 'profile__profession')

默认情况下,搜索将使用不区分大小写的部分匹配。 搜索参数可以包含多个搜索项,其应该是空格和/或逗号分隔。 如果使用多个搜索术语,则仅当所有提供的术语都匹配时才在列表中返回对象。

可以通过在search_fields前面添加各种字符来限制搜索行为。

  • '^' 以指定内容开始.

  • '=' 完全匹配

  • '@' 全文搜索(目前只支持Django的MySQL后端)

  • '$' 正则搜索

例如:

search_fields = ('=username', '=email')

默认情况下,搜索参数名为'search',但这可以通过使用SEARCH_PARAM设置覆盖。

OrderingFilter(排序筛选)

OrderingFilter类支持简单的查询参数控制结果排序。

ordering-filter.png

默认情况下,查询参数名为'ordering',但这可以通过使用ORDERING_PARAM设置覆盖。

例如,按用户名排序用户:

默认情况下,查询参数名为'ordering',但这可以通过使用ORDERING_PARAM设置覆盖。

例如,按用户名排序用户:

http://example.com/api/users?ordering=username

客户端还可以通过为字段名称加上'-'来指定反向排序,如下所示:

http://example.com/api/users?ordering=-username

还可以指定多个排序:

http://example.com/api/users?ordering=account,username

Specifying which fields may be ordered against(指定支持排序的字段)

建议你明确指定API应在ordering filter中允许哪些字段。您可以通过在view中设置ordering_fields属性来实现这一点,如下所示:

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

这有助于防止意外的数据泄漏,例如允许用户针对密码哈希字段或其他敏感数据进行排序。

如果不在视图上指定ordering_fields属性,过滤器类将默认允许用户对serializer_class属性指定的serializer上的任何可读字段进行过滤。

如果你确信视图正在使用的queryset不包含任何敏感数据,则还可以通过使用特殊值'__all__'来明确指定view应允许对任何model字段或queryset进行排序。

class BookingsListView(generics.ListAPIView):
    queryset = Booking.objects.all()
    serializer_class = BookingSerializer
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = '__all__'

Specifying a default ordering(指定默认排序)

如果在view中设置了ordering属性,则将把它用作默认排序。

通常,你可以通过在初始queryset上设置order_by来控制此操作,但是使用view中的ordering参数允许你以某种方式指定排序,然后可以将其作为上下文自动传递到呈现的模板。如果它们用于排序结果的话就能使自动渲染不同的列标题成为可能。

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

ordering属性可以是字符串或字符串的列表/元组。

原文地址:https://www.cnblogs.com/orvis/p/11032537.html