Skip to content
31 changes: 25 additions & 6 deletions rest_framework/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,18 @@ def __new__(cls, name, bases, attrs):


def as_serializer_error(exc):
"""
Coerce validation exceptions into a standardized serialized error format.

This function normalizes both Django's `ValidationError` and REST
framework's `ValidationError` into a dictionary structure compatible
with serializer `.errors`, ensuring all values are represented as
lists of error details.

The returned structure conforms to the serializer error contract:
- Field-specific errors are returned as '{field-name: [errors]}'
- Non-field errors are returned under the 'NON_FIELD_ERRORS_KEY'
"""
assert isinstance(exc, (ValidationError, DjangoValidationError))

if isinstance(exc, DjangoValidationError):
Expand Down Expand Up @@ -815,22 +827,29 @@ def errors(self):

def raise_errors_on_nested_writes(method_name, serializer, validated_data):
"""
Give explicit errors when users attempt to pass writable nested data.
Enforce explicit handling of writable nested and dotted-source fields.

If we don't do this explicitly they'd get a less helpful error when
calling `.save()` on the serializer.
This helper raises clear and actionable errors when a serializer attempts
to perform writable nested updates or creates using the default
`ModelSerializer` behavior.

We don't *automatically* support these sorts of nested writes because
there are too many ambiguities to define a default behavior.
Writable nested relationships and dotted-source fields are intentionally
unsupported by default due to ambiguous persistence semantics. Developers
must either:
- Override the `.create()` / `.update()` methods explicitly, or
- Mark nested serializers as `read_only=True`

This check is invoked internally by default `ModelSerializer.create()`
and `ModelSerializer.update()` implementations.

Eg. Suppose we have a `UserSerializer` with a nested profile. How should
we handle the case of an update, where the `profile` relationship does
not exist? Any of the following might be valid:

* Raise an application error.
* Silently ignore the nested part of the update.
* Automatically create a profile instance.
"""

ModelClass = serializer.Meta.model
model_field_info = model_meta.get_field_info(ModelClass)

Expand Down
Loading