Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override serializer.data in Django REST Framework

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.

like image 662
user2989731 Avatar asked Apr 01 '15 06:04

user2989731


People also ask

How do you pass extra context data to Serializers in Django REST framework?

In function based views we can pass extra context to serializer with "context" parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with "self. context". From example, to get "exclude_email_list" we just used code 'exclude_email_list = self.

Do we need Serializers in Django REST framework?

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.

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.


1 Answers

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.

like image 149
dhke Avatar answered Sep 27 '22 17:09

dhke