【问题标题】:How can I stop django REST framework to show all records if query parameter is wrong如果查询参数错误,如何停止 django REST 框架以显示所有记录
【发布时间】:2015-01-26 18:01:36
【问题描述】:

我正在使用 Django REST Framework,并且我正在使用过滤器来过滤查询集。

http://www.django-rest-framework.org/api-guide/filtering/#filtering-against-query-parameters

喜欢这个

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

但是我已经看到,如果过滤器有错误或查询参数不存在,那么它会显示所有非常糟糕的结果。

如果查询参数有问题,我宁愿没有结果,因为有时我不知道这是否有效

编辑

这是我的代码

class userFilter(django_filters.FilterSet):
    strict = True

    class Meta:
        model = User
        fields = ('is_active', 'is_archived', 'age')

休息

class UserListCreateView(generics.ListCreateAPIView):
    queryset = User.objects.filter(is_archived=False)
    ordering_fields = ('is_active')
    filter_class = userFilter

这是 REST 设置

REST_FRAMEWORK = {
    'DEFAULT_MODEL_SERIALIZER_CLASS':
        'rest_framework.serializers.HyperlinkedModelSerializer',
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_FILTER_BACKENDS': (
        'rest_framework.filters.DjangoFilterBackend',
        'rest_framework.filters.SearchFilter',
        'rest_framework.filters.OrderingFilter',
    ),
    # 'PAGINATE_BY': 1,                 
    'PAGINATE_BY_PARAM': 'page_size',  
    'MAX_PAGINATE_BY': 100,             
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    )
}

【问题讨论】:

  • 你应该发布你的代码..查看它之后会有意义..如果你真的按照你引用的链接..它会导致给出所有结果,因为它返回一个查询集初始化为objects.all,而不是你应该检查query_params,如果不正确返回None ..为了更好的答案吐出你的代码!
  • @vijayshanker 嗨,vijay,我已经添加了代码。请看一下
  • 覆盖 get_queryset 方法.. 并在请求中查找 QUERY_PARAMS 以缩小结果范围.. 应该这样做

标签: django django-rest-framework


【解决方案1】:

如果您使用的是DjangoFilterBackend,请查看strict Non-Meta option

strict 选项控制是否返回结果 用户为任何过滤器字段指定了无效值。经过 默认情况下,strict 设置为 True 意味着一个空的查询集是 如果任何字段包含无效值,则返回。你可以松开这个 通过将 strict 设置为 False 的行为,这将有效地忽略 如果字段的值无效,则过滤字段。

过滤器:

from django_filters.filterset import FilterSet

class UserFilter(FilterSet):
    strict = True

    class Meta:
        model = User
        fields = ['username']

设置:(假设你已经安装了django-filter

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

现在,如果有人这样做:

http://api.example.com/users/?username=myuser&badfilter=1

...它将返回一个空列表,因为badfilter 不存在。

由于FilterSet 自动默认为strict=True,我感觉您没有利用DjangoFilterBackend

【讨论】:

  • @Michale,我试过了,它仍然显示所有记录。我认为有一些设置 REST 而不是过滤器。你能检查一下吗
  • 我需要从您的设置文件中查看您对REST_FRAMEWORK 的设置。抱歉回复延迟。
  • 我已经添加了我的 REST 设置。请看一看。我被困在这个
【解决方案2】:

标记的答案对我不起作用。我通过覆盖“get”方法解决了它:

class UserListCreateView(generics.ListCreateAPIView):
    queryset = User.objects.filter(is_archived=False)
    ordering_fields = ('is_active')
    filter_class = userFilter

    @staticmethod
    def is_valid_query_params(query_params):
        # do validations here
        ...

    def get(self, request, *args, **kwargs):
        if not self.is_valid_query_params(request.query_params):
            return Response([])  # send empty response 
        return super(UserListCreateView, self).get(request, *args, **kwargs)

【讨论】:

  • 这里的情况相同。对于那些使用 ModelViewSet 而不是泛型的人,请记住您应该覆盖 list 而不是 get。问题是,在这种情况下,您还需要覆盖其他方法(操作)(检索、更新等):(
  • 我更喜欢覆盖 get_queryset(个人偏好)。
【解决方案3】:

您的具体问题源于您在 GET 查询中调用的参数未在您的 UserFilter 中定义。因此,DRF 仅考虑以下参数:

fields = ('is_active', 'is_archived', 'age')

此外,strict 仅控制查询参数的如果参数本身存在则不控制。例如

GET mydomain.com/resource_path?whatever=blabla

返回我认为有问题的整个查询集,至少不符合 REST 标准。

我最终写了一个小方法来手动检查请求中传递的查询参数是否真的存在。

【讨论】:

【解决方案4】:

我通过在继承 generics.ListAPIView 的类中重载函数 get_queryset() 来做到这一点。您可以使用 self.request.query_params 检查参数,并为任何情况编写自定义处理程序。

【讨论】:

    【解决方案5】:

    According to the authorstrict 只过滤分配给查询参数的,而不过滤查询参数的存在

    否则诸如分页之类的添加自己的查询参数的东西会破坏 API。

    您可以覆盖get_queryset() 来验证查询键:

    class List(generics.ListAPIView):       
    
        queryset = MyModel.objects.all()                                          
        serializer_class = MyModelSerializer                                       
        filter_fields = ('q1', 'q2',)
        # or filter_class
    
        def get_queryset(self):
            paging = set(['limit', 'offset'])
            qs = super(RestrictedQueryMixin, self).get_queryset()
            # Optional mutual exclusion check below...
            if hasattr(self, 'filter_fields') and hasattr(self, 'filter_class'):
                raise RuntimeError("%s has both filter_fields and filter_class" % self)
            if hasattr(self, 'filter_class'):
                filter_class = getattr(self, 'filter_class', None)
                filters = set(filter_class.get_filters().keys())
            elif hasattr(self, 'filter_fields'):
                filters = set(getattr(self, 'filter_fields', []))
            else:
                filters = set()
            for key in self.request.GET.keys():
                if key in paging:
                    continue
                if key not in filters:
                    return qs.none()
            return qs        
    

    我把它做成了一个mixin。

    或者,您可以提高rest_framework.exceptions.APIException。您也可以从self.paginator.get_schema_fields(self)动态获取分页器字段

    【讨论】:

    • 请注意,如果您使用 django-rest-swagger,则需要将“格式”添加到您忽略的键列表中。
    • 有趣的是你应该提一下——前几天我不得不这样做!
    猜你喜欢
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    • 2019-12-24
    • 2020-03-19
    • 2019-10-16
    • 2014-06-28
    相关资源
    最近更新 更多