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

如何使用drf-spectacular文档化含多数据类型的元组?

DRF-Spectacular无法正确文档化Tuple类型的points字段

问题背景

使用drf-spectacular生成Swagger文档时,视图集直接返回原生字典(未经过DRF序列化器处理),字典结构如下:

data = {
    "lines": List[str],
    "points": List[Tuple[float, float, int, str]],
    "next_failure_date": str,
    "estimate_nth_failure": str,
    "status": str,
}

但Swagger文档中points字段仅被识别为"points": ["string"],无法正确展示Tuple的内部结构。尝试自定义序列化器和字段后仍无效果:

class SwaggerGrowthChartPoint:
    """Class used to generate the Swagger documentation"""

    def __init__(self, x: float, y: float, sap_id: int, created_on: str):
        self.x = x
        self.y = y
        self.sap_id = sap_id
        self.created_on = created_on

class SwaggerGrowthChartPointField(serializers.Field):

    def to_representation(self, value: SwaggerGrowthChartPoint):
        return f"{value.x}, {value.y}, {value.sap_id}, {value.created_on}"
    
    def to_internal_value(self, data):
        return SwaggerGrowthChartPoint(*data)

class SwaggerGrowthChartSerializer(serializers.Serializer):
    """Serializer used to generate the Swagger documentation"""

    lines = SwaggerGrowthChartLinesSerializer(many=True)
    points = serializers.ListField(child=SwaggerGrowthChartPointField())
    next_failure_date = serializers.ListField(child=serializers.DateField())
    estimate_nth_failure = serializers.DateField()
    status = serializers.CharField()

解决方案

方案1:通过@extend_schema手动定义响应Schema

直接在视图集上用@extend_schema装饰器指定响应的OpenAPI结构,精准定义Tuple的每个元素类型:

from drf_spectacular.utils import extend_schema
from rest_framework import viewsets, Response

@extend_schema(
    responses={
        200: {
            "type": "object",
            "properties": {
                "lines": {"type": "array", "items": {"type": "string"}},
                "points": {
                    "type": "array",
                    "items": {
                        "type": "array",
                        "items": [
                            {"type": "number", "format": "float"},
                            {"type": "number", "format": "float"},
                            {"type": "integer"},
                            {"type": "string"}
                        ],
                        "minItems": 4,
                        "maxItems": 4
                    }
                },
                "next_failure_date": {"type": "string", "format": "date"},
                "estimate_nth_failure": {"type": "string", "format": "date"},
                "status": {"type": "string"}
            }
        }
    }
)
class GrowthChartViewSet(viewsets.ViewSet):
    def list(self, request):
        data = {
            "lines": ["line_a", "line_b"],
            "points": [(1.5, 2.7, 1001, "2024-05-01"), (3.2, 4.9, 1002, "2024-05-02")],
            "next_failure_date": "2024-11-30",
            "estimate_nth_failure": "2025-04-15",
            "status": "normal"
        }
        return Response(data)

方案2:调整序列化器并配合extend_schema

修改自定义字段,用@extend_schema_field明确告诉drf-spectacular字段的输出结构,再指定响应序列化器:

from rest_framework import serializers
from drf_spectacular.utils import extend_schema_field, extend_schema
from rest_framework import viewsets, Response

class SwaggerGrowthChartPointField(serializers.Field):
    @extend_schema_field({
        "type": "array",
        "items": [
            {"type": "number", "format": "float"},
            {"type": "number", "format": "float"},
            {"type": "integer"},
            {"type": "string"}
        ],
        "minItems": 4,
        "maxItems": 4
    })
    def to_representation(self, value):
        # 直接返回原Tuple结构,匹配视图返回的数据格式
        return value
    
    def to_internal_value(self, data):
        return tuple(data)

class SwaggerGrowthChartSerializer(serializers.Serializer):
    lines = serializers.ListField(child=serializers.CharField())
    points = serializers.ListField(child=SwaggerGrowthChartPointField())
    next_failure_date = serializers.DateField()
    estimate_nth_failure = serializers.DateField()
    status = serializers.CharField()

@extend_schema(responses=SwaggerGrowthChartSerializer)
class GrowthChartViewSet(viewsets.ViewSet):
    def list(self, request):
        data = {
            # 你的数据逻辑
        }
        return Response(data)

方案3:使用TypedDict自动推断结构(Python 3.8+)

利用Python的TypedDict定义数据结构,让drf-spectacular自动识别并生成正确的Schema:

from typing import TypedDict, List, Tuple
from drf_spectacular.utils import extend_schema
from rest_framework import viewsets, Response

class GrowthChartData(TypedDict):
    lines: List[str]
    points: List[Tuple[float, float, int, str]]
    next_failure_date: str
    estimate_nth_failure: str
    status: str

@extend_schema(responses=GrowthChartData)
class GrowthChartViewSet(viewsets.ViewSet):
    def list(self, request):
        data: GrowthChartData = {
            "lines": ["line1", "line2"],
            "points": [(0.8, 1.9, 2001, "2024-06-01")],
            "next_failure_date": "2024-12-01",
            "estimate_nth_failure": "2025-03-10",
            "status": "warning"
        }
        return Response(data)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:38:11