I have some models
class RootModel(models.Model):
# Some fields
class ElementModel(models.Model):
root = models.ForeignKey(RootModel, related_name='elements', on_delete=models.CASCADE)
class TextModel(ElementModel):
text = models.TextField()
class BooleanModel(ElementModel):
value = models.BooleanField()
a viewset
class RootViewSet(viewsets.ModelViewSet):
queryset = RootModel.objects.all()
serializer_class = RootSerializer
and serializers
class TextSerializer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
class Meta:
model = TextModel
fields = '__all__'
def get_type(self, obj):
return 'TEXT'
class BooleanSerializer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
class Meta:
model = BooleanModel
fields = '__all__'
def get_type(self, obj):
return 'BOOL'
class RootSerializer(WritableNestedModelSerializer):
elements = ...
class Meta:
model = RootModel
fields = '__all__'
WritableNestedModelSerializer comes from drf_writable_nested extension.
I want to GET/POST/PUT a root containing all data
example with GET (same data for POST/PUT)
{
elements: [
{
type: "TEXT",
text: "my awesome text"
},
{
type: "BOOL",
value: true
}
],
...
root fields
...
}
What is the best way for elements field in RootSerializer ?
I also want to have information with OPTIONS method, how can I have it ?
Thanks
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.
The .is_valid() method takes an optional raise_exception flag that will cause it to raise a serializers.ValidationError exception if there are validation errors.
How do I pass Queryset to serializer? To serialize a queryset or list of objects instead of a single object instance, you should pass the many=True flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.
Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
Finally I found a solution.
First we need a PolymorphicSerializer class :
from enum import Enum
from rest_framework import serializers
class PolymorphicSerializer(serializers.Serializer):
"""
Serializer to handle multiple subclasses of another class
- For serialized dict representations, a 'type' key with the class name as
the value is expected: ex. {'type': 'Decimal', ... }
- This type information is used in tandem with get_serializer_map(...) to
manage serializers for multiple subclasses
"""
def get_serializer_map(self):
"""
Return a dict to map class names to their respective serializer classes
To be implemented by all PolymorphicSerializer subclasses
"""
raise NotImplementedError
def to_representation(self, obj):
"""
Translate object to internal data representation
Override to allow polymorphism
"""
if hasattr(obj, 'get_type'):
type_str = obj.get_type()
if isinstance(type_str, Enum):
type_str = type_str.value
else:
type_str = obj.__class__.__name__
try:
serializer = self.get_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 polymorphism
"""
try:
type_str = data['type']
except KeyError:
raise serializers.ValidationError({
'type': 'This field is required',
})
try:
serializer = self.get_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 representation to object
Override to allow polymorphism
"""
serializer = self.get_serializer_map()[validated_data['type']]
validated_data.pop('type')
return serializer(context=self.context).create(validated_data)
def update(self, instance, validated_data):
serializer = self.get_serializer_map()[validated_data['type']]
validated_data.pop('type')
return serializer(context=self.context).update(instance, validated_data)
and now :
class ElementSerializer(PolymorphicSerializer):
class Meta:
model = ElementModel
def get_serializer_map(self):
return {
BooleanSerializer.__class__: BooleanSerializer,
TextSerializer.__class__: TextSerializer,
}
class RootSerializer(WritableNestedModelSerializer):
elements = ElementSerializer(many=True)
class Meta:
model = RootModel
fields = '__all__'
Reference link: https://stackoverflow.com/a/44727343/5367584
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With