Skip to content

Instantly share code, notes, and snippets.

@Michael-J-Ward
Created August 4, 2017 16:42
Show Gist options
  • Save Michael-J-Ward/9e3007571222fc4add0d12eb1a432f4a to your computer and use it in GitHub Desktop.
Save Michael-J-Ward/9e3007571222fc4add0d12eb1a432f4a to your computer and use it in GitHub Desktop.
Implementation of Polymorphic serializer
"""
PolymorphicSerializer Implementation taken from this stack overflow answer:
https://stackoverflow.com/a/44727343/1948982
Copied here to imortalize it to remove the risk of the answer dissappearing
"""
class PolymorphicSerializer(serializers.Serializer):
"""
Serializer to handle multiple subclasses of another class
- `serializer_map` maps class names to their respective serializer classes
- An extra 'type' key is expected for serialized dict representations
"""
serializer_map = {} # type: Dict[str, serializers.Serializer]
def to_representation(self, obj):
"""
Translate object to internal data representation
Override to allow pollymorphism
"""
type_str = obj.__class__.__name__
try:
serializer = self.serializer_map[type_str]
except KeyError:
raise ValueError(
'Serializer for "{}" does not exist'.format(type_str),
)
data = serializer(obj, context=self.context).to_representation(obj)
data['type'] = type_str
return data
def to_internal_value(self, data):
"""
Validate data and initialize primitive types
Override to allow pollymorphism
"""
try:
type_str = data['type']
except KeyError:
raise serializers.ValidationError({
'type': 'This field is required',
})
try:
serializer = self.serializer_map[type_str]
except KeyError:
raise serializers.ValidationError({
'type': 'Serializer for "{}" does not exist'.format(type_str),
})
validated_data = serializer(context=self.context) \
.to_internal_value(data)
validated_data['type'] = type_str
return validated_data
def create(self, validated_data):
"""
Translate validated data represenation to object
Override to allow pollymorphism
"""
serializer = self.serializer_map[validated_data['type']]
return serializer(context=self.context).create(validated_data)
class ParentClassSerializer(PolymorphicSerializer):
"""
Serializer for ParentClass objects
"""
serializer_map = {
ChildClass1.__name__: ChildClass1Serializer,
ChildClass2.__name__: ChildClass2Serializer,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment