diff options
| author | Tom Christie | 2014-10-22 10:32:32 +0100 | 
|---|---|---|
| committer | Tom Christie | 2014-10-22 10:32:32 +0100 | 
| commit | c5d1be8eac6cdb5cce000ec7c55e1847bfcf2359 (patch) | |
| tree | e15672da0e6e72dc2944108e27329a04e1e231bd /docs/topics | |
| parent | 05cbec9dd7f9f0b6a9b59b29ac6c9272b6ae50d8 (diff) | |
| download | django-rest-framework-c5d1be8eac6cdb5cce000ec7c55e1847bfcf2359.tar.bz2 | |
.validate() can raise field errors or non-field errors
Diffstat (limited to 'docs/topics')
| -rw-r--r-- | docs/topics/3.0-announcement.md | 45 | 
1 files changed, 43 insertions, 2 deletions
diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md index 658b50d3..9aeb5df6 100644 --- a/docs/topics/3.0-announcement.md +++ b/docs/topics/3.0-announcement.md @@ -163,7 +163,7 @@ The `validate_<field_name>` method hooks that can be attached to serializer clas              raise serializers.ValidationError('This field should be a multiple of ten.')          return attrs -This is now simplified slightly, and the method hooks simply take the value to be validated, and return it's validated value. +This is now simplified slightly, and the method hooks simply take the value to be validated, and return the validated value.      def validate_score(self, value):          if value % 10 != 0: @@ -172,6 +172,22 @@ This is now simplified slightly, and the method hooks simply take the value to b  Any ad-hoc validation that applies to more than one field should go in the `.validate(self, attrs)` method as usual. +Because `.validate_<field_name>` would previously accept the complete dictionary of attributes, it could be used to validate a field depending on the input in another field. Now if you need to do this you should use `.validate()` instead. + +You can either return `non_field_errors` from the validate method by raising a simple `ValidationError` + +    def validate(self, attrs): +        # serializer.errors == {'non_field_errors': ['A non field error']} +        raise serailizers.ValidationError('A non field error') + +Alternatively if you want the errors to be against a specific field, use a dictionary of when instantiating the `ValidationError`, like so: + +    def validate(self, attrs): +        # serializer.errors == {'my_field': ['A field error']} +        raise serailizers.ValidationError({'my_field': 'A field error'}) + +This ensures you can still write validation that compares all the input fields, but that marks the error against a particular field. +  #### Limitations of ModelSerializer validation.  This change also means that we no longer use the `.full_clean()` method on model instances, but instead perform all validation explicitly on the serializer. This gives a cleaner separation, and ensures that there's no automatic validation behavior on `ModelSerializer` classes that can't also be easily replicated on regular `Serializer` classes. @@ -189,7 +205,32 @@ REST framework 2.x attempted to automatically support writable nested serializat  * It's unclear what behavior the user should expect when related models are passed `None` data.  * It's unclear how the user should expect to-many relationships to handle updates, creations and deletions of multiple records. -Using the `depth` option on `ModelSerializer` will now create **read-only nested serializers** by default. To use writable nested serialization you'll want to declare a nested field on the serializer class, and write the `create()` and/or `update()` methods explicitly. +Using the `depth` option on `ModelSerializer` will now create **read-only nested serializers** by default. + +If you try to use a writable nested serializer without writing a custom `create()` and/or `update()` method you'll see an assertion error when you attempt to save the serializer. For example: + +    >>> class ProfileSerializer(serializers.ModelSerializer): +    >>>     class Meta: +    >>>         model = Profile +    >>>         fields = ('address', 'phone') +    >>> +    >>> class UserSerializer(serializers.ModelSerializer): +    >>>     profile = ProfileSerializer() +    >>>     class Meta: +    >>>         model = User +    >>>         fields = ('username', 'email', 'profile') +    >>> +    >>> data = { +    >>>     'username': 'lizzy', +    >>>     'email': 'lizzy@example.com', +    >>>     'profile': {'address': '123 Acacia Avenue', 'phone': '01273 100200'} +    >>> } +    >>> +    >>> serializer = UserSerializer(data=data) +    >>> serializer.save() +    AssertionError: The `.create()` method does not suport nested writable fields by default. Write an explicit `.create()` method for serializer `UserSerializer`, or set `read_only=True` on nested serializer fields. + +To use writable nested serialization you'll want to declare a nested field on the serializer class, and write the `create()` and/or `update()` methods explicitly.      class UserSerializer(serializers.ModelSerializer):          profile = ProfileSerializer()  | 
