zoukankan      html  css  js  c++  java
  • 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属性可以是字符串或字符串的列表/元组。

  • 相关阅读:
    IOS 自动布局-UIStackPanel和UIGridPanel(三)
    IOS 自动布局-UIStackPanel和UIGridPanel(二)
    IOS 自动布局-UIStackPanel和UIGridPanel(一)
    我的新博客
    Topcoder SRM655 DIV1 500 Nine
    BestCoder Round #38 1002 Greatest Greatest Common Divisor 筛法
    BestCoder Round #38 1001 Four Inages Strategy 暴力
    Google Code Jam 2015 Round 1A Haircut 二分
    Google Code Jam 2015 Round 1A Mushroom Monster 水
    Topcoder SRM656 DIV1 250 RandomPancakeStack 概率DP
  • 原文地址:https://www.cnblogs.com/orvis/p/11032537.html
Copyright © 2011-2022 走看看