Drf-yasg: Can't use Serializer as Schema's object property

Created on 21 Mar 2018  路  6Comments  路  Source: axnsan12/drf-yasg

My APIView returns following object:

out = {
    "foo": FooSerializer(foo, many=True).data,
    "bar": BarSerializer(bar, many=True).data
}

Trying to represent that object by using Serializer references fails with TypeError: Object of type 'SerializerMetaclass' is not JSON serializable:

@swagger_auto_schema(responses={
    200: openapi.Response('OK', openapi.Schema(type=openapi.TYPE_OBJECT, properties={
        'foo': FooSerializer,
        'bar': BarSerializer
    })),
})

Additionally, I don't have these Serializers used anywhere else, so they don't register themselves as definitions, so following fails too:

@swagger_auto_schema(responses={
    200: openapi.Response('OK', openapi.Schema(type=openapi.TYPE_OBJECT, properties={
        'foo': openapi.SchemaRef(openapi.ReferenceResolver('definitions'), 'Foo'),
        'bar': openapi.SchemaRef(openapi.ReferenceResolver('definitions'), 'Bar')
    })),
})

Seems that in such case, defining the whole response structure is the only option, or am I missing some trick here?

Thanks!

question

Most helpful comment

Hello,

Sadly, no, there is currently no such mechanism implemented for recursively converting Serializers inside a Schema object.

Unless you have a good reason not to, it's probably better to use a single serializer for your view result (drf-yasg limitations or not):

class FooBarSerializer(Serializer):
    foo = FooSerializer(many=True)
    bar = BarSerializer(many=True)
out = FooBarSerializer({'foo': foo, 'bar': bar}).data
@swagger_auto_schema(responses={
    200: openapi.Response('OK', FooBarSerializer),
})

All 6 comments

Hello,

Sadly, no, there is currently no such mechanism implemented for recursively converting Serializers inside a Schema object.

Unless you have a good reason not to, it's probably better to use a single serializer for your view result (drf-yasg limitations or not):

class FooBarSerializer(Serializer):
    foo = FooSerializer(many=True)
    bar = BarSerializer(many=True)
out = FooBarSerializer({'foo': foo, 'bar': bar}).data
@swagger_auto_schema(responses={
    200: openapi.Response('OK', FooBarSerializer),
})

Yes, this is where I am headed right now 馃槈

But what about using SchemaRef? Is there a way to "pre-register" schemas based on Serializers?

Unfortunately not, since some aspects of Serializer to Schema conversion can depend on runtime parameters (i.e. the user who is requesting the swagger definition).

Also do note that there is no global ReferenceResolver, and your last example is wrong in any situation because it always tries to get a definition from an empty ReferenceResolver. The instance that is actually used is created for every new run of get_schema, here.

Okay, now I get it - I saw docstring for Schema mentioning SchemaRef and tried to just use it w/o fully understanding the context!

@axnsan12 would it be possible to inspect a serializer class that is not used by any view to include it manually in the Model definitions ? if so, how? I've been looking at the code but still having a hard time trying to do so.

Thanks!

I gotta say I don't quite understand the logic.
If a Schema instance can be substituted with a Serializer instance in a Response, then why not in a Schema property?

Was this page helpful?
0 / 5 - 0 ratings