Django 使用drf yasg,如何在响应中支持多个序列化程序?
由于my drf的响应仅包含单个序列化程序提供的数据,我们可以将其实现为: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)}, ) 这非常好用,但是有些请求会构造一个字典,其中两个或三个键对应于不同的序列化程序,
@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()),
]