oxan/djangorestframework-dataclasses

Difference between inheritance and function

Closed this issue · 3 comments

Hello,

djangorestframework-dataclasses is helping me document my API with drf-spectacular.
Thanks for that.

I noticed a inherited dataclass serializer is different than one created by a function.
An example:

@dataclass
class Monty:
    python: bool

MontySerializer = DataclassSerializer(dataclass=Monty)
class MontyClassSerializer(DataclassSerializer):
    class Meta:
        dataclass = Monty

monty = Monty(True)
MontyClassSerializer(instance = monty) # works
MontySerializer(instance=monty) # TypeError: 'DataclassSerializer' object is not callable

My expectation is that both, class and function would have the same result.
It really doubles my code when it needs to be created as an actual class.
Is there a way around this?

oxan commented

There is no function: what you're doing is calling the constructor of the DataclassSerializer class, which returns a DataclassSerializer instance, not a type. It's meant to be used as substitution for the explicit type in places where you'd instantiate the serializer, not to create a serializer type. E.g. like this:

ser = DataclassSerializer(dataclass=Monty, instance=monty)
# use in place of:
ser = MontyClassSerializer(instance=monty)

Hi, Thank you for the reply. My expectations and what actually happens under the hood were mismatched.
I do think there's value in using the syntax DataclassSerializer(dataclass=Monty) to return a class.
Especially when the use case is documenting the REST API for @api_view functions.

ps. Changed the code example in the top post. MontyClassSerializer now properly inherits from DataclassSerializer.

oxan commented

I do think there's value in using the syntax DataclassSerializer(dataclass=Monty) to return a class.

I'm afraid that's not possible, both because that syntax already has another function, and because technically it's somewhere between very complicated and impossible to implement.

If you really want to create serializers programatically, you can do that with type():

MontySerializer = type('MontySerializer', (DataclassSerializer, ), {'Meta': type('Meta', (), {'dataclass': Monty}})

though you should probably wrap it in another function to keep things readable.