5

I have read a changelog for drf3 but its still unclear for me. Previously i have following serializer:

class TestSerializer(serializers.Serializer):
   att1= serializers.CharField()
   att2= serializers.CharField()
   att3= serializers.CharField(required=False) 

And when i was passing object with only att1 and att2 values in it - it was working fine, no errors, no attribute in the output. But now if i don't pas att3 i got error

Got KeyError when attempting to get a value for field att3 on serializer TestSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the EasyDict instance.
Original exception text was: att3'.

But according to release notes:

required=False: The value does not need to be present in the input

So the code seems valid for me or i don't understand something.

 data = TestSerializer(s.get_results()).data

Where get_results instance of EasyDict with missing att3:

class EasyDict(dict):

  def __init__(self, d=None, **kwargs):
    if d is None:
        d = {}
    if kwargs:
        d.update(**kwargs)
    for k, v in d.items():
        setattr(self, k, v)
    # Class attributes
    for k in self.__class__.__dict__.keys():
        if not (k.startswith('__') and k.endswith('__')):
            setattr(self, k, getattr(self, k))

  def __setattr__(self, name, value):
    if isinstance(value, (list, tuple)):
        value = [self.__class__(x) if isinstance(x, dict) else x for x in value]
    else:
        value = self.__class__(value) if isinstance(value, dict) else value
    super(EasyDict, self).__setattr__(name, value)
    self[name] = value

It was working perfectly fine in drf2, but got this error after upgrading to drf3.

1
  • Can you also include the code you are using this serializer with? Commented Dec 22, 2014 at 14:03

2 Answers 2

5

Django REST Framework uses serializers for both serializing (output) and deserializing (input) data.

It's difficult to tell if you are serializing or deserializing your data in your case, but you will find issues with both, so I'll give you an answer for both cases.


When deserializing data, you should pass in the data to deserialize in using the data keyword argument, and (optionally) the instance to update with the instance keyword argument.

serializer = TestSerializer(data=s.get_results())
if serializer.is_valid():
    data = serializer.data

This should work as expected, up until you call .data on the serializer. This is because calling .data will then serialize the data object again, based on the temporary instance, which you'll learn below is still an issue.

It is important to note that when deserializing data, the required=False parameter will prevent Django REST Framework from requiring that the field is present.


When serializing data, you need to pass a full object representation in using the instance keyword argument, which is also the first positional argument. Django REST Framework expects that the object that is passed in will have all of the fields that you are requesting, even if they are null (None) or blank. The required=False argument does nothing here because we are serialzing data. So you need to ensure that the dictionary (or comparable object) is passed in with all of the keys that the serializer requires.

There is a special case though, when an object is being deserialized and then serialized using the same object. In this case, the underlying object that has been created must still have the optional field, even if the input did not provide it.

Sign up to request clarification or add additional context in comments.

3 Comments

So why required does nothing when we serializing? It was doing a work in drf 2.x. And i dont see anywhere in docs mentioned that it should work for deserializing but shouldn't for serializing.
@Aldarund If it did work in 2.x, I'd create a ticket with DRF about it. At the very least they can mention it as a breaking change. It does specifically say input though.
i have asked in drf google user group, will wait for author answer.
0

I hit the same thing, look inside the code and also read the document, I find:

http://www.django-rest-framework.org/api-guide/serializers/#inspecting-a-modelserializer

Serializing multiple objects

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.

My code for 2.x was:

CollectionSerializer(collections).data

change to:

CollectionSerializer(collections, many=True).data

Problem solved.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.