【djangorestframework】9、Filtering(过滤)

过滤(Filtering)

  • Manager提供的根QuerySet描述了数据库表中的所有对象。但是通常你只需要选择完整对象集的一个子集。--Django文档
  • REST framework的通用列表视图的默认行为是返回模型管理器的整个查询集。通常你会希望API限制查询集返回的条目。
  • 过滤子类GenericAPIView的任何视图的查询集的最简单方法是重写.get_queryset()方法
  • 重写此方法允许你以多种不同方式自定义视图返回的查询集。

过滤当前用户(Filtering against the current user)

  • 你可能希望过滤查询集以确保只返回与当前经过身份验证的用户发出的请求相关的结果。
  • 你可以通过基于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):
        """
        此视图应返回当前已验证用户的所有 purchases 列表。
        """
        user = self.request.user
        return Purchase.objects.filter(purchaser=user)

过滤URL(Filtering against the URL)

  • 另一种过滤方式可能涉及限制基于URL某些部分的查询集
  • 例如,如果URL配置包含这样的条目:
url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
  • 然后,你可以编写一个视图,该视图返回由URL的用户名部分过滤的purchase查询集:
class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        这个视图应该返回由 URL 的用户名部分确定的用户的所有 purchases 列表。
        """
        username = self.kwargs['username']
        return Purchase.objects.filter(purchaser__username=username)

过滤查询参数(Filtering against query parameters)

class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        通过过滤 URL 中的 `username` 查询参数,可以选择将返回的 purchases 限制为给定的用户。
        """
        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)

  • 除了能够重写默认的查询集外,REST frameworl还包括对通用过滤后端的支持,允许你轻松地构建复杂的搜索和过滤器
  • 通过过滤器还可以在可浏览的API和管理API中将自身显示为HTML控件。

设置过滤器后端(Setting filter backends)

  • 可以使用DEFAULT_FILTER_BACKENDS setting全局设置默认的过滤器后端。例如:
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
  • 你还可以使用基于类的视图(GenericAPIView),在每个视图或每个视图集的基础上设置过滤器后端
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,)

过滤和对象查找(Filtering and object lookups)

  • 请注意,如果为视图配置了过滤器后端,那么除了用于过滤列表视图之外,它还将用于过滤返回单个对象的查询集。
  • 例如,给定前面的示例以及ID为4675的产品,以下URL将返回响应的对象,或返回404响应,具体取决于给定的产品实例是否满足过滤田间:
http://example.com/api/products/4675/?category=clothing&max_price=10.0

重写初始查询集(Overriding the initial queryset)

  • 请注意,你可以同时使用重写的.get_queryset()和通用过滤,并且一切都将按预期工作。例如,如果Product与User(名为purchase)有多对多的关系,则你可能需要编写像这样的视图:
class PurchasedProductsList(generics.ListAPIView):
    """
    Return a list of all the products that the authenticated
    user has ever purchased, with optional filtering.
    """
    model = Product
    serializer_class = ProductSerializer
    filter_class = ProductFilter

    def get_queryset(self):
        user = self.request.user
        return user.purchase_set.all()

API指南(API Guide)

DjangoFilterBackend

  • django-filter库包含DjangoFilterBackend类,它支持REST framework高度自定义字段过滤
  • 要使用DjangoFilterBackend,首先要安装django-filter然后将django_filters添加到Django的INSTALLED_APPS中
pip install django-filter
  • 你现在应该将过滤器后端添加到你的设置:
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
  • 或者将过滤器后端添加到单个视图或视图集
from django_filters.rest_framework import DjangoFilterBackend

class UserListView(generics.ListAPIView):
    ...
    filter_backends = (DjangoFilterBackend,)
  • 如果你需要的是简单的基于等式的过滤,则可以在视图或视图集上设置filter_fields属性,列出你想要过滤的一组字段。
class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('category', 'in_stock')
  • 这将自动为给定字段创建一个FilterSet类,并允许你发出如下请求:
http://example.com/api/products?category=clothing&in_stock=True
  • 对于更高级的过滤要求,你可以指定视图应使用的FilterSet类。你可以在django-filter文档中阅读有关FilterSet的更多信息。还建议你阅读有关DRF integration的部分。

SearchFilter

  • SearchFilter类支持简单的基于单个查询参数的搜索,并且基于Django 管理员的搜索功能
  • 在使用时,可浏览的API将包含SearchFilter控件:
search-filter.png
  • 仅当视图具有search_fields属性集时,才会应用SearchFilter类search_fields属性应该是模型上文本类型字段的名称列表,例如CharField或TextField
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执行相关查找
earch_fields = ('username', 'email', 'profile__profession')
  • 默认情况下,搜索将使用不区分大小写的部分匹配。搜索参数可能包含多个搜索项,它们应该是空格和/或逗号分隔的。如果使用多个搜索项,则只有在所有提供的项匹配的情况下,对象才会返回到列表中。
  • 可以通过在search_fields之前添加各种字符来限制搜索行为。
    • '^'开始搜索
    • '='完全匹配
    • '@'全文搜索(目前只支持Django的MySQL后端)
    • '$'正则表达式搜索。
  • 举个例子:
search_fields = ('=username', '=email')
  • 默认情况下,搜索参数被命名为'search',但这可能会被SEARCH_PARAM设置覆盖。
  • 有关更多详细信息,请参阅Django文档。

OrderingFilter

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

  • 默认情况下,查询参数被命名为'ordering',但这可能会被ORDERING_PARAM设置覆盖
  • 例如,要按username对用户排序:
http://example.com/api/users?ordering=username
  • 客户端还可以通过在字段名称前加上'-'来指定反向排序,如下所示
http://example.com/api/users?ordering=-username
  • 还可以指定多个排序:
http://example.com/api/users?ordering=account,username
posted @ 2022-04-25 16:05  郭祺迦  阅读(326)  评论(0)    收藏  举报