I'm trying to add fields dynamically to a serializer of Django Rest Framework, by overwriting the __init__ method. The approach is similar to the one described here: http://masnun.com/2015/10/21/django-rest-framework-dynamic-fields-in-serializers.html
The reason I'm doing this is, because I want to change the field type dynamically to a one, determined by the property type_ of the instance to be serialized. This works pretty well, if I serialize one instance at a time:
from rest_framework import serializers
from rest_framework.fields import empty
class VariableDetails:
def __init__(self, name, type_, value):
self.name = name
self.type_ = type_
self.value = value
class VariableDetailSerializer(serializers.Serializer):
TYPE_FIELD_MAP = {
'string': serializers.CharField,
'integer': serializers.IntegerField,
'float': serializers.FloatField,
}
name = serializers.CharField()
type_ = serializers.CharField()
def __init__(self, instance=None, data=empty, **kwargs):
# this is where the magic happens
super().__init__(instance, data, **kwargs)
if instance is not None:
field_type = self.TYPE_FIELD_MAP[instance.type_]
self.fields['value'] = field_type()
string_details = VariableDetails('character value', 'string', 'hello world')
integer_details = VariableDetails('integer value', 'integer', 123)
print(VariableDetailSerializer(string_details).data)
# {'name': 'character value', 'type_': 'string', 'value': 'hello world'}
print(VariableDetailSerializer(integer_details).data)
# {'name': 'integer value', 'type_': 'integer', 'value': 123}
If I want to serialize multiple instances of VariableDetails that are related to a parent instance (calling it Parent for the example), the value field is missing:
class Parent:
def __init__(self, variable_details):
self.variable_details = variable_details
class ParentSerializer(serializers.Serializer):
variable_details = VariableDetailSerializer(many=True)
parent = Parent(variable_details=[string_details, integer_details])
print(ParentSerializer(parent).data)
# {
# 'variable_details': [
# {
# 'name': 'character_value',
# 'type_': 'string'
# # value is missing
# },
# {
# 'name': 'integer_value',
# 'type_': 'integer'
# },
# ]
# }
Apparently VariableDetailSerializer.__init__ is only called during the creation of the ParentSerializer and once when a new instance of the ParentSerializer is initialized. In both cases instance is None. Hence, it is not called for each of the VariableDetails.
Does anybody know how to add fields dynamically to a Serializer that is also serializing list instances?
To facilitate running the code, I created a gist: https://gist.github.com/larsrinn/861f8d50bf5bb0626d73321b546d8cb3 The code should be copy&pastable into a python repl, if Django Rest Framework is installed. However, you don't need to create a Django Project