aboutsummaryrefslogtreecommitdiffstats
path: root/docs/topics
diff options
context:
space:
mode:
authorTom Christie2014-10-22 10:32:32 +0100
committerTom Christie2014-10-22 10:32:32 +0100
commitc5d1be8eac6cdb5cce000ec7c55e1847bfcf2359 (patch)
treee15672da0e6e72dc2944108e27329a04e1e231bd /docs/topics
parent05cbec9dd7f9f0b6a9b59b29ac6c9272b6ae50d8 (diff)
downloaddjango-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.md45
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()