Django中使用drf_yasg嵌套序列化器时出现Swagger生成错误
解决方案
核心原因
drf_yasg默认会尝试将请求序列化器解析为表单(form-data)参数,但表单格式不支持嵌套的JSON结构,因此在处理带many=True的嵌套序列化器时会抛出无法实例化的错误。
方法1:强制视图使用JSON请求格式
在视图中明确指定解析器为JSON,并通过drf_yasg的装饰器标记请求内容类型为application/json,让drf_yasg按照JSON结构生成文档:
from rest_framework.parsers import JSONParser from drf_yasg.utils import swagger_auto_schema from rest_framework.response import Response from rest_framework.views import APIView class CarCreateView(APIView): parser_classes = [JSONParser] # 强制使用JSON解析器 @swagger_auto_schema( request_body=CarSerializer, consumes=["application/json"], # 指定请求内容类型为JSON responses={201: CarSerializer} ) def post(self, request): serializer = CarSerializer(data=request.data) if serializer.is_valid(): # 重写create方法处理嵌套的CarFiles保存 serializer.save() return Response(serializer.data, status=201) return Response(serializer.errors, status=400)
同时,确保CarSerializer重写了create方法来处理嵌套数据的保存:
class CarSerializer(serializers.ModelSerializer): car_files = CarFilesSerializer(many=True) class Meta: model = Car fields = '__all__' def create(self, validated_data): # 提取嵌套的文件数据 files_data = validated_data.pop('car_files') # 创建Car实例 car = Car.objects.create(**validated_data) # 批量创建关联的CarFiles for file_data in files_data: CarFiles.objects.create(car=car, **file_data) return car
方法2:拆分输入输出序列化器
分别定义用于POST请求的输入序列化器和用于GET请求的输出序列化器,在视图中根据请求方法切换:
# 输入序列化器:处理POST请求的嵌套数据提交 class CarCreateSerializer(serializers.ModelSerializer): car_files = CarFilesSerializer(many=True) class Meta: model = Car fields = '__all__' def create(self, validated_data): files_data = validated_data.pop('car_files') car = Car.objects.create(**validated_data) for file_data in files_data: CarFiles.objects.create(car=car, **file_data) return car # 输出序列化器:处理GET请求的嵌套数据返回 class CarSerializer(serializers.ModelSerializer): car_files = CarFilesSerializer(many=True, read_only=True) class Meta: model = Car fields = '__all__'
视图中切换序列化器:
class CarView(APIView): def get_serializer_class(self): if self.request.method == 'POST': return CarCreateSerializer return CarSerializer def get(self, request): cars = Car.objects.all() serializer = self.get_serializer()(cars, many=True) return Response(serializer.data) @swagger_auto_schema( request_body=CarCreateSerializer, consumes=["application/json"], responses={201: CarSerializer} ) def post(self, request): serializer = self.get_serializer()(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=201) return Response(serializer.errors, status=400)
方法3:自定义drf_yasg字段检查器
通过自定义字段检查器,拦截drf_yasg的字段解析逻辑,让它正确识别嵌套序列化器为JSON Schema的一部分:
from drf_yasg.inspectors import FieldInspector from drf_yasg import openapi from rest_framework import serializers class NestedSerializerInspector(FieldInspector): def field_to_swagger_object(self, field, swagger_object_type, use_references=True): # 处理带many=True的嵌套序列化器 if hasattr(field, 'child') and isinstance(field.child, serializers.ModelSerializer): if swagger_object_type == openapi.Items: # 直接返回子序列化器的Schema定义 return self.probe_field_inspectors(field.child, openapi.Schema, use_references) # 其他情况使用默认逻辑 return super().field_to_swagger_object(field, swagger_object_type, use_references)
在Django配置文件中添加这个自定义检查器:
SWAGGER_SETTINGS = { 'DEFAULT_FIELD_INSPECTORS': [ 'your_app_name.inspectors.NestedSerializerInspector', # 替换为你的检查器路径 'drf_yasg.inspectors.FieldInspector', 'drf_yasg.inspectors.ReferencingSerializerInspector', 'drf_yasg.inspectors.ChoiceFieldInspector', 'drf_yasg.inspectors.FileFieldInspector', 'drf_yasg.inspectors.DictFieldInspector', 'drf_yasg.inspectors.SimpleFieldInspector', 'drf_yasg.inspectors.StringDefaultFieldInspector', ], }
内容的提问来源于stack exchange,提问作者Kaç Thon
相关产品推荐
相关产品推荐

