Django 使用drf yasg,如何在响应中支持多个序列化程序?

Django 使用drf yasg,如何在响应中支持多个序列化程序?,django,django-rest-framework,swagger,Django,Django Rest Framework,Swagger,由于my drf的响应仅包含单个序列化程序提供的数据,我们可以将其实现为: @swagger_auto_schema( operation_id='ID example', operation_description="Description example.", responses={status.HTTP_200_OK: Serializer4ModelA(many=True)}, ) 这非常好用,但是有些请求会构造一个字典,其中两个或三个键对应于不同的序列化程序,

由于my drf的响应仅包含单个序列化程序提供的数据,我们可以将其实现为:

@swagger_auto_schema(
    operation_id='ID example',
    operation_description="Description example.",
    responses={status.HTTP_200_OK: Serializer4ModelA(many=True)},
)
这非常好用,但是有些请求会构造一个字典,其中两个或三个键对应于不同的序列化程序,例如

response = {
    "a": serializer_data_for_model_a,
    "b": serializer_data_for_model_b,
    "c": serializer_data_for_model_c
}
我们如何在自动模式中描述这一点?我尝试了几种不同的方法,主要类似于以下方法:

@swagger_auto_schema(
    operation_id='ID example',
    operation_description="Description example.",
    responses={status.HTTP_200_OK: openapi.Response(
        description='response description',
        schema=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'a': Serializer4ModelA(many=True),
                'b': Serializer4ModelB(many=True),
                'c': Serializer4ModelC(many=True)
            })
    )}
)
但是加载文档时总是失败,
flex
说:

"/usr/local/lib/python3.6/site-packages/flex/utils.py", line 125, in 
get_type_for_value raise ValueError("Unable to identify type of 
{0}".format(repr(value)))
ValueError: Unable to identify type of 
Serializer4ModelA(many=True):

我已经一遍又一遍地阅读文档,在github上搜索了一个例子,但我找不到一个例子或任何人这样做。因此,我的问题是如何成功地为响应手动定义一个模式,该响应在返回的响应中包含针对不同键的不同序列化程序?

我最终能够做到这一点,尽管可能不是最优雅的解决方案,但它确实有效

我的drf有一个自定义的应用程序标签格式,所以我的所有应用程序都在一个文件夹中,让我们称这个文件夹为
apps

在我的问题中,对于序列化程序,我们可以使用自定义函数替换
openapi.Schema
properties
部分中的
Serializer4ModelA
,比如
get\u serializer(Serializer4ModelA())

因此,我的想法是通过自动获取信息并自动构建
属性
字典,基本上自己构建模式。这是一个非常粗糙的方法,但对我来说很有用,因为在我的文档中,我还想为Dynamodb传递序列化程序,所以我为Dynamodb序列化程序创建了一个非常类似的函数

我只是刚刚做了,而且很有效,但是显然需要更多的注意来覆盖
字段映射中的所有字段,更好地处理
序列化方法字段

但无论如何,这是一个有效的解决方案,但不是通用的,调整和东西将不得不根据您的特定项目

我大致实现了以下功能:

from drf_yasg import openapi
from drf_yasg.inspectors import SwaggerAutoSchema
from drf_yasg.utils import swagger_auto_schema
from drf_yasg.inspectors import FieldInspector
from drf_yasg.utils import swagger_serializer_method
import rest_framework

rest_framework_openapi_field_mapping = {
     "ListField": openapi.TYPE_ARRAY,
     "CharField": openapi.TYPE_STRING,
     "BooleanField": openapi.TYPE_BOOLEAN,
     "FloatField": openapi.TYPE_NUMBER,
     "DateTimeField": openapi.TYPE_STRING,
     "IntegerField": openapi.TYPE_INTEGER,
     "SerializerMethodField": openapi.TYPE_STRING
}

def parse_rest_framework_field(field):
    rest_framework_field_type = field.split("(")[0]
    openapi_field_type = 
    rest_framework_openapi_field_mapping[rest_framework_field_type]
    if "help_text=" in field:
        field_description = field.split("help_text='")[-1].split("'")[0]
    else:
        field_description = None
    return openapi.Schema(type=openapi_field_type, description=field_description)

def parse_serializer(serializer):
    properties = {}
    for k,v in serializer.get_fields().items():
        if v.__module__ == "rest_framework.fields":
            properties[k] = parse_rest_framework_field(str(v))
        elif v.__module__.startswith("apps."):
            serializer = str(v).strip().split("(")[0]
            exec(f"from {v.__module__} import {serializer}")
            eval_serializer = eval(f"{serializer}()")
            properties[k] = openapi.Schema(type=openapi.TYPE_OBJECT, properties=parse_serializer(eval_serializer))
        else:
            pass
    return properties

def get_serializer(serializer, description):
    """ Needs to return openapi.Schema() """
    properties = parse_serializer(serializer)
    return_openapi_schema = openapi.Schema( type=openapi.TYPE_OBJECT, properties=properties, description=description)
    return return_openapi_schema

我通常做的是创建另一个序列化程序(这样drf yasg就可以生成文档)

例如,如果我有一个端点返回:

{
“结果”:[…带有序列化程序X的序列化结果列表]
}
我创建了第二个序列化程序:

Y类(序列化程序。序列化程序):
结果=X(多个=真)

并在swagger_auto_schema decorator中使用
Y
序列化程序。

我遇到了这个问题,正在寻找除了我最初的解决方案(与@Hernan解释的方法相同)之外的其他方法,但没有找到。
drf_yasg.openapi.Schema
(drf_yasg==1.20.0)的代码表明它不接受任何序列化程序对象。正如@Hernan所说,解决这个问题的方法是使用一个额外的序列化程序,并在那里定义嵌套的子序列化程序。然后,直接或通过
openapi.Response.schema
将其传递给
swagger\u auto\u schema.responses
(如下所示):

输出:

很有效,非常感谢,顺便问一下,有没有一种代码更少的更简单的方法?
from django.urls import path
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers, status, views


class Serializer4ModelA(serializers.Serializer):
    dog = serializers.CharField(label="My dog is a good boy")
class Serializer4ModelB(serializers.Serializer):
    perro = serializers.CharField(label="Mi perro es un buen chico")
    hund = serializers.CharField(label="Mein Hund ist ein guter Junge")
    aso = serializers.CharField(label="Ang aso ko ay mabait na bata")
class Serializer4ModelC(serializers.Serializer):
    eey = serializers.CharField(label="Eygaygu waa wiil fiican")
class SampleResponseSerializer(serializers.Serializer):
    a = Serializer4ModelA(many=True)
    b = Serializer4ModelB(many=True)
    c = Serializer4ModelC(many=True)


class SampleView(views.APIView):
    @swagger_auto_schema(
        responses={
            status.HTTP_200_OK: openapi.Response(
                description="response description",
                schema=SampleResponseSerializer,
            )
        }
    )
    def get(self, request):
        pass

urlpatterns = [
    path("sample/", SampleView.as_view()),
]