Django休息框架验证分页限制和偏移

时间:2016-11-14 08:46:38

标签: python django pagination django-rest-framework

Django Rest Framework默认情况下会吞下针对无效limitoffset值引发的异常,即使它们不是整数并返回默认限制和偏移值。
此外,没有min_offsetmin_limit因此它允许在限制和偏移中使用负值。
我需要在我的API中对这些情况提出错误。
我已经构建了一个自定义分页类来覆盖paginate_queryset方法并在那里进行了验证。是否有API来验证最小限制和最小偏移值。我有以下代码,我自己验证它。

是否可以在方法中为paginator编写验证,因为文档中没有提及它,或者我需要在我的viewset方法本身内验证?

class CustomPagination(pagination.LimitOffsetPagination):
    default_limit = 25
    max_limit = 50
    min_limit = 1
    min_offset = 1
    max_offset = 50

    def paginate_queryset(self, queryset, request, view=None):
        limit = request.query_params.get('limit')
        offset = request.query_params.get('offset')

        if limit:
            limit = int(limit)
            if limit > self.max_limit:
                raise serializers.ValidationError({"limit" : ["Limit should be less than or equal to {0}".format(self.max_limit)]})
            elif limit < self.min_limit:
                raise serializers.ValidationError({"limit" : ["Limit should be greater than or equal to {0}".format(self.min_limit)]})
        if offset:
            offset = int(offset)
            if offset > self.max_offset:
                raise serializers.ValidationError({"offset" : ["Offset should be less than or equal to {0}".format(self.max_offset)]})
            elif offset < self.min_offset:
                raise serializers.ValidationError({"offset" : ["Offset should be greater than or equal to {0}".format(self.min_offset)]})

        return super(self.__class__, self).paginate_queryset(queryset, request, view)

1 个答案:

答案 0 :(得分:1)

如果您查看LimitOffsetPagination上的DRf代码,您会看到它使用两种方法来解析limitoffset

  • get_limit()

    def get_limit(self, request):
        if self.limit_query_param:
            try:
                return _positive_int(
                    request.query_params[self.limit_query_param],
                    strict=True,
                    cutoff=self.max_limit
                )
            except (KeyError, ValueError):
                pass
    
        return self.default_limit
    
  • get_offset()

    def get_offset(self, request):
        try:
            return _positive_int(
                request.query_params[self.offset_query_param],
            )
        except (KeyError, ValueError):
            return 0
    

正如您所看到的,可以在这两种方法中处理可能的异常。

因此,您可以轻松覆盖这些方法,也无需重新发明轮子。
使方法捕获异常并再次raise

class CustomPagination(pagination.LimitOffsetPagination):
    default_limit = 25
    max_limit = 50
    min_limit = 1
    min_offset = 1
    max_offset = 50

    def get_limit(self, request):
        if self.limit_query_param:
            try:
                return _positive_int(
                    request.query_params[self.limit_query_param],
                    strict=True,
                    cutoff=self.max_limit
                )
            except (KeyError, ValueError) as e:
                raise e  # Re-raise the caught exception

        return self.default_limit

    def get_offset(self, request):
        try:
            return _positive_int(
                request.query_params[self.offset_query_param],
            )
        except (KeyError, ValueError) as e:
            raise e  # Re-raise the caught exception

注意:
虽然前面提到的工作,但每次用户传递错误的参数时你的应用程序崩溃都会非常不方便,你应该考虑使用它。