Skip to main content
 首页 » 编程设计

python之Django rest 框架验证分页限制和偏移量

2025年04月02日25sxdcgaq8080

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

是否可以在方法内部编写分页器验证,因为文档中没有提及它,还是我需要在我的 View 集方法本身内部进行验证?

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) 

请您参考如下方法:

如果您查看 LimitOffsetPagination 上的 DRf 代码你会看到它使用两种方法来解析 limit 和 offset:

  • 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 
    

如您所见,可能的异常是在这两个方法中处理的。

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

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 

注意:
尽管上述方法有效,但每次用户向其传递错误参数时应用程序崩溃都会非常不便,您应该考虑使用它。