I have tried to add a key serializer.data['test'] = 'asdf'
, this does not appear to do anything.
I want to transform the representation of a key's value. To do this, I'm trying to use the value to calculate a new value and replace the old one in the dictionary.
This is what I want to accomplish, but I don't know why the value is not being replaced. There are no errors thrown, and the resulting dictionary has no evidence that I've tried to replace anything:
class PlaceDetail(APIView):
def get(self, request, pk, format=None):
place = Place.objects.select_related().get(pk=pk)
serializer = PlaceSerializer(place)
#serializer.data['tags'] = pivot_tags(serializer.data['tags'])
serializer.data['test'] = 'asdf'
print(serializer.data['test'])
return Response(serializer.data)
Terminal: KeyError: 'test'
I have observed by printing that serializer.data
is a dictionary.
I have also tested that the syntax I'm trying to use should work:
>>> test = {'a': 'Alpha'}
>>> test
{'a': 'Alpha'}
>>> test['a']
'Alpha'
>>> test['a'] = 'asdf'
>>> test
{'a': 'asdf'}
How can I properly modify the serializer.data
dictionary?
The Serializer.data
property returns an OrderedDict
which is constructed using serializer._data
. The return value is not serializer._data
itself.
Thus changing the return value of serializer.data
does not change serializer._data
member. As a consequence, the following calls to serializer.data
are not changed.
# In class Serializer(BaseSerializer)
@property
def data(self):
ret = super(Serializer, self).data
return ReturnDict(ret, serializer=self)
# In class ReturnDict(OrderedDict)
def __init__(self, *args, **kwargs):
self.serializer = kwargs.pop('serializer')
super(ReturnDict, self).__init__(*args, **kwargs)
You can keep a copy of the return value of serializer.data
, which is an ordered dictionary, and manipulate it as you wish.
Example:
# keep the return value of serializer.data
serialized_data = serializer.data
# Manipulate it as you wish
serialized_data['test'] = 'I am cute'
# Return the manipulated dict
return Response(serialized_data)
Why:
If you look at the source code of Django Restframework, you will see that in Serializer
class,
Serializer._data
is just a normal dictionary. Serializer.data
is a method decorated to act like a property. It returns a ReturnDict
object, which is a customized class derived from OrderedDict
. The returned ReturnDict
object is initialized using key/value pairs in Serializer._data
.If Serializer.data
returns Serializer._data
directly, then your original method will work as you expected. But it won't work since it's returning another dictionary-like object constructed using Serializer._data
.
Just keep in mind that the return value of Serializer.data
is not Serializer._data
, but an ordered dictionary-like object. Manipulating the return value does not change Serializer._data
.
I believe the reason why serializer.data
does not return serializer._data
directly is to avoid accidental change of the data and to return a pretty representation of serializer._data
.
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