drf-yasg嵌套序列化器Swagger文档缺失openning_time字段及报错解决
问题分析与解决方案
问题根源
openning_time字段在序列化器中设置了read_only=True,Swagger自动生成请求体时会忽略只读字段,因为这类字段不属于请求参数范畴。- 使用
manual_parameters添加IN_BODY参数的方式不符合drf-yasg规范,它要求请求体必须通过request_body参数传入Schema或Serializer对象,这是触发报错的直接原因。
方案一:实现支持嵌套更新的序列化器(推荐)
如果需要实际接收并处理openning_time的更新数据,需要创建专用的更新序列化器,并手动实现嵌套字段的更新逻辑:
1. 修改序列化器
# serializers.py class WarehouseUpdateSerializer(serializers.ModelSerializer): # 移除read_only=True,允许接收请求中的openning_time数据 openning_time = OpenningTimeSerializer(many=True) class Meta: model = Warehouse fields = ['pk', 'name', 'action_available', 'openning_time', 'workers'] # 覆盖update方法,处理嵌套的开放时间数据 def update(self, instance, validated_data): # 提取嵌套的开放时间数据 openning_times_data = validated_data.pop('openning_time', None) # 先更新Warehouse本身的字段 instance = super().update(instance, validated_data) # 根据业务逻辑处理开放时间的更新(示例:删除旧数据后创建新数据) if openning_times_data: instance.openning_time.all().delete() for time_data in openning_times_data: OpenningTime.objects.create(warehouse=instance, **time_data) return instance
2. 配置Swagger视图
# views.py from drf_yasg.utils import swagger_auto_schema class WarehouseApi(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): queryset = Warehouse.objects.all() serializer_class = WarehouseSerializer permission_classes = [IsAuthenticated, ] @swagger_auto_schema( request_body=WarehouseUpdateSerializer, responses={200: WarehouseSerializer} ) def update(self, request, *args, **kwargs): # 指定更新操作使用的序列化器 self.serializer_class = WarehouseUpdateSerializer return super().update(request, *args, **kwargs)
方案二:仅在Swagger中显示字段(临时需求)
如果不需要实际处理嵌套更新,只是希望Swagger文档中显示openning_time字段,可以直接用openapi.Schema定义请求体结构:
# views.py from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi class WarehouseApi(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): queryset = Warehouse.objects.all() serializer_class = WarehouseSerializer permission_classes = [IsAuthenticated, ] @swagger_auto_schema( request_body=openapi.Schema( type=openapi.TYPE_OBJECT, properties={ 'name': openapi.Schema(type=openapi.TYPE_STRING), 'action_available': openapi.Schema(type=openapi.TYPE_BOOLEAN), 'workers': openapi.Schema(type=openapi.TYPE_INTEGER), 'openning_time': openapi.Schema( type=openapi.TYPE_ARRAY, items=openapi.Schema( type=openapi.TYPE_OBJECT, properties={ 'weekday': openapi.Schema(type=openapi.TYPE_INTEGER), 'from_hour': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_TIME), 'to_hour': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_TIME), }, required=['weekday', 'from_hour', 'to_hour'] ) ) }, required=['name'] # 根据实际业务设置必填字段 ), responses={200: WarehouseSerializer} ) def update(self, request, *args, **kwargs): return super().update(request, *args, **kwargs)
注意事项
- DRF默认不会自动处理嵌套序列化器的更新逻辑,必须手动覆盖
update方法实现业务逻辑。 read_only=True会让字段仅出现在响应中,若需要在请求中接收该字段,必须移除该参数或调整为write_only=True(仅写入不返回)。
内容的提问来源于stack exchange,提问作者Pytolong
相关产品推荐
相关产品推荐

