[Django]-What are the differences between data and validated data?

22👍

You can customize data in your CommentSerializer.validate_content method:

This is your serializer:

class CommentSerializer(serializers.Serializer):
    email=serializers.EmailField()
    content=serializers.CharField()
    def validate_content(self,value):
        #If content is 'baz' returns 'foo'
        if value and value == "baz":
            return "foo"
        return value

Let’s try with wrong values (for email):

>>> serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})

>>> serializer.data
Traceback (most recent call last):
    raise AssertionError(msg)
AssertionError: When a serializer is passed a `data` keyword  argument 
you must call `.is_valid()` before attempting to access the 
serialized `.data` representation.

You should either call .is_valid() first, or access .initial_data instead.

>>> serializer.initial_data
{'content': 'baz', 'email': 'foobar'}

>>> serializer.validated_data
Traceback (most recent call last):
   raise AssertionError(msg) 
AssertionError: You must call `.is_valid()` before accessing `.validated_data`.

>>> serializer.is_valid()
False

>>> serializer.data
{'content': 'baz', 'email': 'foobar'}

>>> serializer.validated_data
{}

>>> serializer.errors
{'email': [u'Enter a valid email address.']}

Now Let’s try with correct values

>>> serializer2 = CommentSerializer(data={'email': 'foobar@email.it', 
'content': 'baz'})  
>>> serializer2.is_valid()
True

>>> serializer2.initial_data
{'content': 'baz', 'email': 'foobar@email.it'}
>>> serializer2.errors
{}

>>> serializer2.data
{'content': u'foo', 'email': u'foobar@email.it'}

>>> serializer2.validated_data
OrderedDict([(u'email', u'foobar@email.it'), (u'content', u'foo')])

So:

  • data : is a dict and you can see it only after is_valid() (you can see only not validated values)
  • validated_data is an OrderedDict and you can see it only after is_valid() and is_valid() == True

16👍

data and validated_data will not always be the same.
For example:

class UserSerializer(serializers.Serializer):
    name = serializers.CharField()
    phone = serializers.CharField(required=False, allow_null=True)

We could get different data:

>>> user = UserSerializer(data={'name': 'Foo'})
>>> user.is_valid()
True
>>> user.data
{'name': 'Foo', 'phone': None}
>>> user.validated_data
{'name': 'Foo'}

Based on BaseSerializer internal code, data property is just self.to_representation(self.validated_data) whenever the serializer has been validated:

elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
    self._data = self.to_representation(self.validated_data)

And in this case to_representation internal code sets to None those cases.


Because of this behaviour I would recommend using validated_data over data. If you used data with a serializer like this, and explicitly sets attributes to an object based on data, you could set to None attributes that did not exist in initial data.

11👍

DESERIALIZING

Data is the input to a Serializer
eg

serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})

As you can see email is invalid, so the following rule apply(from official docmentation)

When deserializing data, you always need to call is_valid() before
attempting to access the validated data, or save an object instance

serializer.is_valid()

If the data your trying to deserialize is valid #True then you can access the validated data as

serializer.validated_data

ADDITION

There is no data transformation after validation, it only check if your data is valid, if any validation errors occur, the .errors property will contain a dictionary representing the resulting error messages.

A good example is when your doing field validation

class CommentSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    
    def validate_title(self, value):
        if 'django' not in value.lower():
           raise serializers.ValidationError("Title is not about Django")
        return value

validate_title will called each time you call .is_valid(), as you can see it only check if the title is django related, if True the value which in this case title is returned else ValidationError is raised. NO CHANGE OF DATA HERE

Leave a comment