When you're writing a serializer, it is trivial to specify which fields will be included (via Meta
's fields
), setting read/write permissions on them and validating them. However, I was wondering if there is an easy way to specify that only the fields that are included are to be expected and any extra keys passed in should raise an error.
E.g. say, I have a serializer
class ModelASerializer(serializers.ModelSerializer): class Meta: model = models.ModelA fields = ('name', 'number')
Supposed further that I don't have any validations.
And I'm POST
ing this payload to create a new instance
{ "name": "test", "number": 5 }
Everything is fine.
But suppose my API has changed and now I'm also storing a new field, title
, but forget to update my serializer. Clients will be sending payloads that look like
{ "name": "test", "number": 5, "title": "Mr" }
However the serializer will simply ignore the extra key, not raising an exception.
So, my question is: is there any way to make a serializer only expect fields specified in fields
or -- if it's not a ModelSerializer
-- fields, specified as members, and raise an error if it's not the case?
The generic views use the raise_exception=True flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above. By default this exception results in a response with the HTTP status code "400 Bad Request".
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.
serializer_class - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the get_serializer_class() method.
Came across this question and found that using object level validation is a bit easier. This entails simply defining a validate method:
class ModelASerializer(serializers.ModelSerializer): ... def validate(self, data): if hasattr(self, 'initial_data'): unknown_keys = set(self.initial_data.keys()) - set(self.fields.keys()) if unknown_keys: raise ValidationError("Got unknown fields: {}".format(unknown_keys)) return data
You can do that by overriding the is_valid()
method of the serializer. Here, we will check if any of the key in the payload
is not a serializer field using filter()
and lambda
functions.
If filter()
returns some fields which are not in the serializer fields, then we raise a ValidationError
. Else, we call the super()
method and it will then perform the normal serializer validation.
from django.core.exceptions import ValidationError class MySerializer(..): def is_valid(self, raise_exception=False): if hasattr(self, 'initial_data'): payload_keys = self.initial_data.keys() # all the payload keys serializer_fields = self.fields.keys() # all the serializer fields extra_fields = filter(lambda key: key not in serializer_fields , payload_keys) if extra_fields: raise ValidationError('Extra fields %s in payload'%extra_fields) return super(MySerializer, self).is_valid(raise_exception)
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