Skip to content

Commit 6c5339a

Browse files
committed
Handle unset fields with 'many=True'
The docs note: When serializing fields with dotted notation, it may be necessary to provide a `default` value if any object is not present or is empty during attribute traversal. However, this doesn't work for fields with 'many=True'. When using these, the default is simply ignored. The solution is simple: do in 'ManyRelatedField' what we were already doing for 'Field', namely, catch possible 'AttributeError' and 'KeyError' exceptions and return the default if there is one set. Signed-off-by: Stephen Finucane <[email protected]> Closes: #7550
1 parent 91916a4 commit 6c5339a

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

rest_framework/relations.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from django.utils.translation import gettext_lazy as _
1111

1212
from rest_framework.fields import (
13-
Field, empty, get_attribute, is_simple_callable, iter_options
13+
Field, SkipField, empty, get_attribute, is_simple_callable, iter_options
1414
)
1515
from rest_framework.reverse import reverse
1616
from rest_framework.settings import api_settings
@@ -531,7 +531,30 @@ def get_attribute(self, instance):
531531
if hasattr(instance, 'pk') and instance.pk is None:
532532
return []
533533

534-
relationship = get_attribute(instance, self.source_attrs)
534+
try:
535+
relationship = get_attribute(instance, self.source_attrs)
536+
except (KeyError, AttributeError) as exc:
537+
if self.default is not empty:
538+
return self.get_default()
539+
if self.allow_null:
540+
return None
541+
if not self.required:
542+
raise SkipField()
543+
msg = (
544+
'Got {exc_type} when attempting to get a value for field '
545+
'`{field}` on serializer `{serializer}`.\nThe serializer '
546+
'field might be named incorrectly and not match '
547+
'any attribute or key on the `{instance}` instance.\n'
548+
'Original exception text was: {exc}.'.format(
549+
exc_type=type(exc).__name__,
550+
field=self.field_name,
551+
serializer=self.parent.__class__.__name__,
552+
instance=instance.__class__.__name__,
553+
exc=exc
554+
)
555+
)
556+
raise type(exc)(msg)
557+
535558
return relationship.all() if hasattr(relationship, 'all') else relationship
536559

537560
def to_representation(self, iterable):

0 commit comments

Comments
 (0)