You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF Spectacular错误响应示例被分页结构包裹,如何解决?

问题

我为ArchiveListView的GET接口配置了两种响应:

  • 200状态返回分页列表(使用ArchiveListViewSerializer)
  • 400状态返回错误信息(使用ExceptionSerializer)

期望400的响应示例为:

{
    "api_status_code": "DATE_PARSE_ERROR",
    "extra": {
        "details": "asdf"
    }
}

但Swagger UI及生成的OpenAPI文档中,该示例被分页结构(包含count、next、previous、results)错误包裹,生成的OpenAPI片段显示示例被嵌套在results中,不过响应Schema是正确指向Exception的。

相关实现代码如下:

class ExceptionSerializer(serializers.Serializer):
    api_status_code = serializers.CharField()
    extra = serializers.DictField(required=False)

@extend_schema_view(
    get=extend_schema(
        responses={
            200: OpenApiResponse(
                response=s.ArchiveListViewSerializer,
                examples=[],
            ),
            400: OpenApiResponse(
                response=ExceptionSerializer,
                examples=[
                    OpenApiExample(
                        "DATE_PARSE_ERROR",
                        value={"api_status_code": "DATE_PARSE_ERROR", "extra": {"details": "asdf"}},
                        status_codes=[400],
                        response_only=True,
                    )
                ],
            ),
        },
    )
)
class ArchiveListView(LoginRequiredMixin, ListAPIView):
    model = m.Archive
    serializer_class = s.ArchiveListViewSerializer
    pagination_class = LimitOffsetPagination
解决方案

问题根源在于ListAPIView默认启用分页逻辑,drf-spectacular会自动为List视图的响应添加分页包装,即使你为400状态指定了非分页的ExceptionSerializer,框架仍可能错误套用分页结构。

可以通过以下两种方式解决:

方式一:在400响应中明确禁用分页

修改OpenApiResponse配置,添加pagination=False参数,告知drf-spectacular该响应不需要分页包装:

400: OpenApiResponse(
    response=ExceptionSerializer,
    pagination=False,  # 新增此行,禁用分页包装
    examples=[
        OpenApiExample(
            "DATE_PARSE_ERROR",
            value={"api_status_code": "DATE_PARSE_ERROR", "extra": {"details": "asdf"}},
            status_codes=[400],
            response_only=True,
        )
    ],
),

方式二:从视图层面控制分页触发

重写视图的get_pagination_class方法,仅在响应状态为200时启用分页:

class ArchiveListView(LoginRequiredMixin, ListAPIView):
    model = m.Archive
    serializer_class = s.ArchiveListViewSerializer
    pagination_class = LimitOffsetPagination

    def get_pagination_class(self):
        # 仅在请求成功返回200时使用分页
        if not hasattr(self, 'response') or self.response.status_code == 200:
            return self.pagination_class
        return None

第一种方式直接针对Swagger文档生成逻辑修正,操作简单;第二种方式从视图业务逻辑层面确保异常响应不会被分页处理,能同步修正文档和实际接口的响应格式。

内容的提问来源于stack exchange,提问作者jnowak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:35:33