当前位置: 代码迷 >> 综合 >> Filtering - Django REST framework
  详细解决方案

Filtering - Django REST framework

热度:102   发布时间:2023-09-14 11:03:28.0

过滤-Django REST框架

filters.py

过滤

Manager提供的根QuerySet描述数据库表中的所有对象。但是,通常您只需要选择完整对象集的一个子集。

— Django文档

REST框架的泛型列表视图的默认行为是返回模型管理器的整个查询集。通常,您希望API限制查询集返回的项。

筛选子类的任意视图的查询集的最简单方法GenericAPIView是覆盖.get_queryset()方法。

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

对当前用户进行筛选

您可能希望筛选查询集,以确保只返回与发出请求的当前身份验证用户相关的结果。

通过基于request.user.

例如:

from myapp.models import Purchase
from myapp.serializers import PurchaseSerializer
from rest_framework import genericsclass PurchaseList(generics.ListAPIView):serializer_class = PurchaseSerializerdef get_queryset(self):"""This view should return a list of all the purchasesfor the currently authenticated user."""user = self.request.userreturn Purchase.objects.filter(purchaser=user)

过滤URL

另一种过滤方式可能涉及根据URL的某些部分限制查询集。

例如,如果您的URL配置包含如下条目:

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

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

class PurchaseList(generics.ListAPIView):serializer_class = PurchaseSerializerdef get_queryset(self):"""This view should return a list of all the purchases forthe user as determined by the username portion of the URL."""username = self.kwargs['username']return Purchase.objects.filter(purchaser__username=username)

对查询参数进行过滤

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

我们可以覆盖.get_queryset()来处理URL,例如http://example.com/api/purchases?username=denvercoder9,并仅在以下情况下筛选查询集:username参数包含在URL中:

class PurchaseList(generics.ListAPIView):serializer_class = PurchaseSerializerdef 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

泛型过滤

除了能够覆盖默认的查询集之外,REST框架还包括对通用筛选后端的支持,这些后端允许您轻松地构造复杂的搜索和筛选器。

泛型过滤器也可以在可浏览API和ADMIN API中显示为HTML控件。

[图片上传中...(image-bd557e-1572570872118-2)]

设置滤波器后端

默认筛选器后端可以全局设置,使用DEFAULT_FILTER_BACKENDS背景。例如。

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 genericsclass UserListView(generics.ListAPIView):queryset = User.objects.all()serializer_class = UserSerializerfilter_backends = [django_filters.rest_framework.DjangoFilterBackend]

过滤和对象查找

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

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

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

重写初始查询集

请注意,可以同时使用重写的.get_queryset()和通用过滤一起,一切都会像预期的那样工作。例如,如果Product与.有着多到多的关系User,命名purchase,您可能需要编写这样的视图:

class PurchasedProductsList(generics.ListAPIView):"""Return a list of all the products that the authenticateduser has ever purchased, with optional filtering."""model = Productserializer_class = ProductSerializerfilterset_class = ProductFilterdef get_queryset(self):user = self.request.userreturn user.purchase_set.all()

API指南

DjangoFilterBackend

这个django-filter库包括DjangoFilterBackend类,它支持REST框架的高度自定义字段筛选。

使用DjangoFilterBackend,第一次安装django-filter...然后添加django_filters去Django‘sINSTALLED_APPS

pip install django-filter

现在,您应该将筛选器后端添加到您的设置中:

REST_FRAMEWORK = {'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}

或将筛选器后端添加到单个视图或视图集。

from django_filters.rest_framework import DjangoFilterBackendclass UserListView(generics.ListAPIView):...filter_backends = [DjangoFilterBackend]

如果只需要简单的基于等式的筛选,则可以设置filterset_fields属性,列出要对其进行筛选的字段集。

class ProductList(generics.ListAPIView):queryset = Product.objects.all()serializer_class = ProductSerializerfilter_backends = [DjangoFilterBackend]filterset_fields = ['category', 'in_stock']

这将自动创建一个FilterSet为给定字段初始化,并允许您发出请求,如:

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

对于更高级的筛选要求,可以指定FilterSet应由视图使用的。你可以读到更多关于FilterSet在Django-过滤器文档...我们还建议您阅读DRF集成.

探测仪

这个探测仪类支持简单的基于单个查询参数的搜索,并且基于Django管理员的搜索功能.

在使用时,可浏览API将包括探测仪管制:

[图片上传中...(image-722ba5-1572570872118-1)]

这个探测仪类仅在视图具有search_fields属性集这个search_fields属性应该是模型上文本类型字段的名称列表,如CharFieldTextField.

from rest_framework import filtersclass UserListView(generics.ListAPIView):queryset = User.objects.all()serializer_class = UserSerializerfilter_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后端。)
  • ‘$’Regex搜索。

例如:

search_fields = ['=username', '=email']

默认情况下,搜索参数名为'search',但是这可能会被SEARCH_PARAM背景。

若要根据请求内容动态更改搜索字段,可以将探测仪并覆盖get_search_fields()功能。例如,下面的子类将只搜索title如果查询参数title_only在请求中:

from rest_framework import filtersclass CustomSearchFilter(filters.SearchFilter):def get_search_fields(self, view, request):if request.query_params.get('title_only'):return ['title']return super(CustomSearchFilter, self).get_search_fields(view, request)

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


OrderingFilter

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

[图片上传中...(image-c4418b-1572570872118-0)]

默认情况下,查询参数名为'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

指定可对哪些字段进行排序。

建议您显式地指定API应该允许在排序过滤器中的哪些字段。您可以通过设置ordering_fields属性,如下所示:

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

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

如果你指定ordering_fields属性时,筛选器类默认为允许用户对序列化程序指定的序列化程序上的任何可读字段进行筛选。serializer_class属性。

如果您确信视图使用的查询集不包含任何敏感数据,则还可以显式指定视图应允许在任何使用特殊值的模型字段或queryset聚合'__all__'.

class BookingsListView(generics.ListAPIView):queryset = Booking.objects.all()serializer_class = BookingSerializerfilter_backends = [filters.OrderingFilter]ordering_fields = '__all__'

指定默认排序

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

通常,您可以通过设置order_by在初始查询集上,但是使用ordering参数允许您指定排序,然后将其作为上下文自动传递给呈现的模板。这样,如果使用列标题对结果进行排序,就可以以不同的方式自动呈现列标题。

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

这个ordering属性可以是字符串,也可以是字符串的列表/元组。


自定义泛型过滤

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

若要这样做,请重写BaseFilterBackend,并覆盖.filter_queryset(self, request, queryset, view)方法。该方法应该返回一个新的过滤查询集。

除了允许客户端执行搜索和筛选之外,泛型筛选后端还可以用于限制对任何给定请求或用户应该可见的对象。

例如,您可能需要限制用户只能看到他们创建的对象。

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

我们可以通过重写get_queryset()在视图上,但是使用过滤器后端允许您更容易地将此限制添加到多个视图,或者将其应用于整个API。

自定义接口

通用过滤器还可以在可浏览API中显示接口。要做到这一点,您应该实现to_html()方法,该方法返回筛选器的呈现HTML表示形式。此方法应具有以下签名:

to_html(self, request, queryset, view)

该方法应返回呈现的HTML字符串。

分页与模式

还可以通过实现get_schema_fields()方法。此方法应具有以下签名:

get_schema_fields(self, view)

方法应该返回coreapi.Field实例。

第三方包

下面的第三方包提供了额外的过滤器实现。

Django REST框架过滤器包

这个Django-REST-框架-过滤器包与DjangoFilterBackend类,并允许您轻松地跨关系创建筛选器,或为给定字段创建多个筛选器查找类型。

Django REST框架全文搜索过滤器

这个djangorestframework-word-filter作为替代物filters.SearchFilter它将搜索全文或完全匹配的单词。

Django URL过滤器

Django-url-过滤器提供了一种安全的方法来通过友好的人机界面过滤数据。它的工作原理与DRF序列化器和字段非常相似,因为它们可以嵌套,但它们被称为过滤器集和过滤器。这提供了过滤相关数据的简单方法。此外,这个库是通用的,因此它可以用于筛选其他数据源,而不仅仅是Django。QuerySetS.

DRF-url-过滤器

DRF-url滤波器是一个简单的Django应用程序,可以在drf上应用过滤器。ModelViewSetQueryset以一种干净、简单和可配置的方式。它还支持对传入的查询参数及其值进行验证。一个漂亮的蟒蛇包Voluptuous用于对传入的查询参数进行验证。有趣的地方在于,您可以根据查询参数的要求定义自己的验证。

  相关解决方案