如果查询参数错误,如何停止django REST框架以显示所有记录

时间:2022-06-12 02:51:22

I am using Django REST Framework and i am using filters to filter the query set.

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

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

like this

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

But i have seen that if there is error in filters or the query parameters does not exist then it displays all results which is very bad.

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

I rather want no results if there is issue with query parameters because sometimes i don't know if that is working or not

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

EDIT

This is my code

这是我的代码

class userFilter(django_filters.FilterSet):
    strict = True

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

REST

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

This is REST settings

这是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',
    )
}

4 个解决方案

#1


3  

If you are using the DjangoFilterBackend, take a look at the strict Non-Meta option.

如果您使用的是DjangoFilterBackend,请查看严格的Non-Meta选项。

The strict option controls whether results are returned when an invalid value is specified by the user for any filter field. By default, strict is set to True meaning that an empty queryset is returned if any field contains an invalid value. You can loosen this behavior by setting strict to False which will effectively ignore a filter field if its value is invalid.

strict选项控制在用户为任何过滤器字段指定无效值时是否返回结果。默认情况下,strict设置为True,表示如果任何字段包含无效值,则返回空的查询集。您可以通过将strict设置为False来放松此行为,如果其值无效,则会有效地忽略过滤器字段。

The filter:

from django_filters.filterset import FilterSet

class UserFilter(FilterSet):
    strict = True

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

The settings: (assumes you have installed django-filter)

设置:(假设您已安装django-filter)

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

Now, if someone does:

现在,如果有人这样做:

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

...it will return an empty list, as badfilter does not exist.

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

As the FilterSet automatically defaults to strict=True, I have a feeling that you are not taking advantage of the DjangoFilterBackend.

由于FilterSet自动默认为strict = True,我觉得你没有利用DjangoFilterBackend。

#2


1  

The marked answer didn't work for me. I solved it by overriding the "get" method:

明确的答案对我不起作用。我通过覆盖“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)

#3


1  

Your specific issue arises from the fact that the parameters you invoke in your GET query are not defined in your UserFilter. Thus only the following parameters will be taken into account from DRF:

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

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

Moreover strict only controls the value of a query parameter, not if the parameter itself exists. For example

而且strict仅控制查询参数的值,而不是参数本身存在。例如

GET mydomain.com/resource_path?whatever=blabla

returns the whole queryset which is something wrong in my opinion, at least not REST-compliant.

返回整个查询集,这在我看来是错误的,至少不符合REST。

I ended up writing a small method to manually check if the query parameters passed in the request actually exist.

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

#4


0  

According to the author, strict only filters the values assigned to the query parameters, not the existence of the query parameters.

根据作者,strict只过滤分配给查询参数的值,而不是查询参数的存在。

Otherwise things such as paging, which add its own query parameters, would break the API.

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

You can override get_queryset() to validate the query keys:

您可以覆盖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        

I made this into a mixin.

我把它变成了混合物。

Alternatively, you could raise rest_framework.exceptions.APIException. You can also alternatively get the paginator fields dynamically from self.paginator.get_schema_fields(self)

或者,您可以引发rest_framework.exceptions.APIException。您也可以从self.paginator.get_schema_fields(self)动态获取paginator字段。

#1


3  

If you are using the DjangoFilterBackend, take a look at the strict Non-Meta option.

如果您使用的是DjangoFilterBackend,请查看严格的Non-Meta选项。

The strict option controls whether results are returned when an invalid value is specified by the user for any filter field. By default, strict is set to True meaning that an empty queryset is returned if any field contains an invalid value. You can loosen this behavior by setting strict to False which will effectively ignore a filter field if its value is invalid.

strict选项控制在用户为任何过滤器字段指定无效值时是否返回结果。默认情况下,strict设置为True,表示如果任何字段包含无效值,则返回空的查询集。您可以通过将strict设置为False来放松此行为,如果其值无效,则会有效地忽略过滤器字段。

The filter:

from django_filters.filterset import FilterSet

class UserFilter(FilterSet):
    strict = True

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

The settings: (assumes you have installed django-filter)

设置:(假设您已安装django-filter)

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

Now, if someone does:

现在,如果有人这样做:

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

...it will return an empty list, as badfilter does not exist.

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

As the FilterSet automatically defaults to strict=True, I have a feeling that you are not taking advantage of the DjangoFilterBackend.

由于FilterSet自动默认为strict = True,我觉得你没有利用DjangoFilterBackend。

#2


1  

The marked answer didn't work for me. I solved it by overriding the "get" method:

明确的答案对我不起作用。我通过覆盖“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)

#3


1  

Your specific issue arises from the fact that the parameters you invoke in your GET query are not defined in your UserFilter. Thus only the following parameters will be taken into account from DRF:

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

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

Moreover strict only controls the value of a query parameter, not if the parameter itself exists. For example

而且strict仅控制查询参数的值,而不是参数本身存在。例如

GET mydomain.com/resource_path?whatever=blabla

returns the whole queryset which is something wrong in my opinion, at least not REST-compliant.

返回整个查询集,这在我看来是错误的,至少不符合REST。

I ended up writing a small method to manually check if the query parameters passed in the request actually exist.

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

#4


0  

According to the author, strict only filters the values assigned to the query parameters, not the existence of the query parameters.

根据作者,strict只过滤分配给查询参数的值,而不是查询参数的存在。

Otherwise things such as paging, which add its own query parameters, would break the API.

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

You can override get_queryset() to validate the query keys:

您可以覆盖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        

I made this into a mixin.

我把它变成了混合物。

Alternatively, you could raise rest_framework.exceptions.APIException. You can also alternatively get the paginator fields dynamically from self.paginator.get_schema_fields(self)

或者,您可以引发rest_framework.exceptions.APIException。您也可以从self.paginator.get_schema_fields(self)动态获取paginator字段。