官方原文链接

过滤

REST framework 的通用列表视图的默认行为是从模型管理器返回整个查询集。通常你会希望 API 限制查询集返回的条目。

筛选 GenericAPIView 子类的查询集的最简单方法是重写 .get_queryset() 方法。

重写此方法允许你以多种不同方式自定义视图返回的查询集。

根据当前用户进行过滤

你可能需要过滤查询集,以确保只返回与当前通过身份验证的用户发出的请求相关的结果。

你可以基于 request.user 的值进行筛选来完成此操作。

例如:

  1. from myapp.models import Purchase
  2. from myapp.serializers import PurchaseSerializer
  3. from rest_framework import generics
  4. class PurchaseList(generics.ListAPIView):
  5. serializer_class = PurchaseSerializer
  6. def get_queryset(self):
  7. """
  8. This view should return a list of all the purchases
  9. for the currently authenticated user.
  10. """
  11. user = self.request.user
  12. return Purchase.objects.filter(purchaser=user)

根据 URL 进行过滤

另一种过滤方式可能涉及基于 URL 的某个部分限制查询集。

例如,如果你的 URL 配置包含这样的条目:

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

然后,你可以编写一个视图,返回由 URL 的用户名部分过滤的 purchase 查询集:

  1. class PurchaseList(generics.ListAPIView):
  2. serializer_class = PurchaseSerializer
  3. def get_queryset(self):
  4. """
  5. This view should return a list of all the purchases for
  6. the user as determined by the username portion of the URL.
  7. """
  8. username = self.kwargs['username']
  9. return Purchase.objects.filter(purchaser__username=username)

根据查询参数进行过滤

过滤初始查询集的最后一个例子是根据 url 中的查询参数确定初始查询集。

我们可以覆盖 .get_queryset() 来处理诸如 http://example.com/api/purchases?username=denvercoder9 的URL,并且只有在 URL 中包含 username 参数时才过滤查询集:

  1. class PurchaseList(generics.ListAPIView):
  2. serializer_class = PurchaseSerializer
  3. def get_queryset(self):
  4. """
  5. Optionally restricts the returned purchases to a given user,
  6. by filtering against a `username` query parameter in the URL.
  7. """
  8. queryset = Purchase.objects.all()
  9. username = self.request.query_params.get('username', None)
  10. if username is not None:
  11. queryset = queryset.filter(purchaser__username=username)
  12. return queryset

通用过滤器

除了能够覆盖默认的查询集外,REST framework 还包括对通用过滤后端的支​​持,使你可以轻松构建复杂的搜索和过滤器。

通用过滤器也可以在可浏览的 API 和管理 API 中将自己渲染为 HTML 控件。

Filter Example

设置过滤器后端

可以使用 DEFAULT_FILTER_BACKENDS setting 全局设置默认的过滤器后端。例如。

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

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

  1. import django_filters.rest_framework
  2. from django.contrib.auth.models import User
  3. from myapp.serializers import UserSerializer
  4. from rest_framework import generics
  5. class UserListView(generics.ListAPIView):
  6. queryset = User.objects.all()
  7. serializer_class = UserSerializer
  8. filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)

过滤和对象查找

请注意,如果为一个视图配置了一个过滤器后端,那么除了用于筛选列表视图之外,它还将用于筛选返回单个对象的查询集。

例如,根据前面的示例以及 ID 为 4675 的产品,以下 URL 将返回相应的对象,或返回 404 响应,具体取决于给定产品实例是否满足过滤条件:

  1. http://example.com/api/products/4675/?category=clothing&max_price=10.00

覆盖初始查询集

请注意,你可以同时重写的 .get_queryset() 和通用过滤,并且所有内容都将按预期工作。例如,如果产品与用户具有多对多关系,则可能需要编写一个如下所示的视图:

  1. class PurchasedProductsList(generics.ListAPIView):
  2. """
  3. Return a list of all the products that the authenticated
  4. user has ever purchased, with optional filtering.
  5. """
  6. model = Product
  7. serializer_class = ProductSerializer
  8. filter_class = ProductFilter
  9. def get_queryset(self):
  10. user = self.request.user
  11. return user.purchase_set.all()

API 参考

DjangoFilterBackend

django-filter 库包含一个 DjangoFilterBackend 类,它支持 REST framework 对字段过滤进行高度定制。

要使用 DjangoFilterBackend,首先安装 django-filter。然后将 django_filters 添加到 Django 的 INSTALLED_APPS

  1. pip install django-filter

你现在应该将过滤器后端添加到设置中:

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

或者将过滤器后端添加到单个视图或视图集。

  1. from django_filters.rest_framework import DjangoFilterBackend
  2. class UserListView(generics.ListAPIView):
  3. ...
  4. filter_backends = (DjangoFilterBackend,)

如果你只需要简单的基于等式的过滤,则可以在视图或视图集上设置 filter_fields 属性,列出你要过滤的一组字段。

  1. class ProductList(generics.ListAPIView):
  2. queryset = Product.objects.all()
  3. serializer_class = ProductSerializer
  4. filter_backends = (DjangoFilterBackend,)
  5. filter_fields = ('category', 'in_stock')

这将自动为给定字段创建一个 FilterSet 类,并允许你发出如下请求:

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

对于更高级的过滤要求,你应该在视图上在指定 FilterSet 类。你可以在 django-filter 文档中阅读有关 FilterSet 的更多信息。还建议你阅读 DRF integration

SearchFilter

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

在使用时,可浏览的 API 将包含一个 SearchFilter 控件:

Search Filter

SearchFilter 类将仅在视图具有 search_fields 属性集的情况下应用。search_fields 属性应该是模型上文本类型字段的名称列表,例如 CharFieldTextField

  1. class UserListView(generics.ListAPIView):
  2. queryset = User.objects.all()
  3. serializer_class = UserSerializer
  4. filter_backends = (filters.SearchFilter,)
  5. search_fields = ('username', 'email')

这将允许客户端通过查询来过滤列表中的项目,例如:

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

你还可以使用查找 API 双下划线表示法对 ForeignKey 或 ManyToManyField 执行相关查找:

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

默认情况下,搜索将使用不区分大小写的部分匹配。搜索参数可能包含多个搜索词,它们应该是空格和(或)逗号分隔的。如果使用多个搜索条件,则只有在所有提供的条件匹配的情况下,对象才会返回到列表中。

搜索行为可以通过将各种字符预先添加到 search_fields 来限制。

  • ‘^’ 匹配起始部分。
  • ‘=’ 完全匹配。
  • ‘@’ 全文搜索。(目前只支持 Django 的 MySQL 后端。)
  • ‘$’ 正则匹配。

例如:

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

默认情况下,搜索参数被命名为 'search' ,但这可能会被 SEARCH_PARAM setting 覆盖。

有关更多详细信息,请参阅 Django 文档


OrderingFilter

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

Ordering Filter

默认情况下,查询参数被命名为 'ordering',但这可能会被 ORDERING_PARAM setting 覆盖。

例如,要通过 username 对用户排序:

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

客户端也可以通过在字段名称前加 ‘ - ‘ 来指定反向排序,如下所示:

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

也可以指定多个排序:

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

指定可以根据哪些字段进行排序

建议你明确指定 API 应该允许在排序过滤器中使用哪些字段。你可以通过在视图上设置一个 ordering_fields 属性来完成此操作,如下所示:

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

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

如果你未在视图上指定 ordering_fields 属性,则过滤器类将默认允许用户过滤由 serializer_class 属性指定的序列化类中的任何可读字段。

如果你确信视图使用的查询集不包含任何敏感数据,则还可以通过使用特殊值 '__all__' 明确指定视图允许在任何模型字段或查询集聚合上进行排序。

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

指定默认顺序

如果在视图上设置了 ordering 属性,则将用作默认排序。

通常情况下,你应该通过在初始查询集上设置 order_by 来控制此操作,但是通过在视图上使用 ordering 参数,你可以指定排序方式,然后可以将其作为上下文自动传递到渲染的模板。这可以自动渲染列标题,如果它们用于排序结果。

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

ordering 属性可以是一个字符串或者字符串列表(元组)。


DjangoObjectPermissionsFilter

DjangoObjectPermissionsFilter 旨在与 django-guardian 软件包一起使用,添加了自定义 'view' 的权限。过滤器将确保查询集仅返回用户具有适当查看权限的对象。

如果你使用的是 DjangoObjectPermissionsFilter,那么你可能还需要添加适当的对象权限类,以确保用户只有在具有适当对象权限的情况下才能对实例进行操作。做到这一点的最简单方法是继承 DjangoObjectPermissions 并为 perms_map 属性添加 'view' 权限。

使用 DjangoObjectPermissionsFilterDjangoObjectPermissions 的完整示例可能如下所示。

permissions.py:

  1. class CustomObjectPermissions(permissions.DjangoObjectPermissions):
  2. """
  3. Similar to `DjangoObjectPermissions`, but adding 'view' permissions.
  4. """
  5. perms_map = {
  6. 'GET': ['%(app_label)s.view_%(model_name)s'],
  7. 'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
  8. 'HEAD': ['%(app_label)s.view_%(model_name)s'],
  9. 'POST': ['%(app_label)s.add_%(model_name)s'],
  10. 'PUT': ['%(app_label)s.change_%(model_name)s'],
  11. 'PATCH': ['%(app_label)s.change_%(model_name)s'],
  12. 'DELETE': ['%(app_label)s.delete_%(model_name)s'],
  13. }

views.py:

  1. class EventViewSet(viewsets.ModelViewSet):
  2. """
  3. Viewset that only lists events if user has 'view' permissions, and only
  4. allows operations on individual events if user has appropriate 'view', 'add',
  5. 'change' or 'delete' permissions.
  6. """
  7. queryset = Event.objects.all()
  8. serializer_class = EventSerializer
  9. filter_backends = (filters.DjangoObjectPermissionsFilter,)
  10. permission_classes = (myapp.permissions.CustomObjectPermissions,)

自定义通用过滤器

你还可以提供自己的通用过滤器后端,或者编写一个可供其他开发人员使用的可安装应用程序。

为此,请继承 BaseFilterBackend,并覆盖 .filter_queryset(self, request, queryset, view) 方法。该方法应该返回一个新的,过滤的查询集。

除了允许客户端执行搜索和过滤外,通用过滤器后端可用于限制哪些对象应该对给定的请求或用户可见。

举个栗子

你可能需要限制用户只能看到他们创建的对象。

  1. class IsOwnerFilterBackend(filters.BaseFilterBackend):
  2. """
  3. Filter that only allows users to see their own objects.
  4. """
  5. def filter_queryset(self, request, queryset, view):
  6. return queryset.filter(owner=request.user)

我们可以通过覆盖视图上的 get_queryset()来实现相同的行为,但使用过滤器后端允许你更轻松地将此限制添加到多个视图,或者将其应用于整个 API。

自定义接口

通用过滤器也可以在可浏览的 API 中渲染接口。为此,你应该实现一个 to_html() 方法,该方法返回过滤器的渲染 HTML 表示。此方法应具有以下签名:

to_html(self, request, queryset, view)

该方法应该返回一个渲染的 HTML 字符串。

Pagination & schemas

通过实现 get_schema_fields() 方法,你还可以使过滤器控件可用于 REST framework 提供的模式自动生成。此方法应具有以下签名:

get_schema_fields(self, view)

该方法应该返回一个 coreapi.Field 实例列表。