Reputation: 1359
I've been trying to alter the value of a form field the Django REST Framework's admin panel and for some reason the change never takes place. I have the serializer below
class SomeView(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
# I Want to override this and change the POST data
def perform_create(self, serializer):
user = self.request.user.id
# this was a form field where I manually entered the user ID
# I now want it to default to the logged in user
serializer.data['user'] = user
# This returns the original user that was entered into the form field
print serializer.data
I checked out serializer.data with dir()
and it's just a python dictionary so I can't figure out why I can't modify the value. As a test, I tried to add extra values but that doesn't work either
# this doesnt work
serializer.data['some_new_field'] = 'test'
EDIT
On another note, I can copy the data and edit it
fake_data = serializer.data.copy()
fake_data['old_value'] = 'new value'
However, it always fails to validate
serializer = MyModelSerializer(data=fake_data)
serializer.is_valid() # returns false
EDIT EDIT:
Ok, so the validation error was caused by Django returning a SimpleLazyObject. Everything works now when I perform a copy of the data, but I'm really curious as to why I can't edit serializer.data
directly without copying it. The problem is solved now, but if anyone can provide insight on the issue just for curiosity, that would be awesome.
Upvotes: 15
Views: 8525
Reputation: 15388
I checked out serializer.data with dir() and it's just a python dictionary so I can't figure out why I can't modify the value.
While the value returned from Serializer.data
is indeed a dictionary, Serializer.data
is not a simple instance variable.
If you look at rest_framework/serializers.py
:
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
# [...]
@property
def data(self):
ret = super().data
return ReturnDict(ret, serializer=self)
ReturnDict
inherits from OrderedDict
, but you still get a new dictionary every time you access Serializer.data
.
The real data is in _data
, however as noted by the underscore you might not want to modify that either as it is not intended to be public. The values are filled by Serializer.to_representation()
which you could override on the viewset.
As for the second part: ModelViewSet
defines get_serializer()
that is called with the request POST data to create the serializer you want to modify. I'd suggest try to change the input data before the serializer is created, instead.
Upvotes: 15