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 <stephen@that.guru>
Closes: #7550
This commit is contained in:
Stephen Finucane 2020-10-03 20:00:56 +01:00
parent 91916a4db1
commit 6c5339ac14

View File

@ -10,7 +10,7 @@ from django.utils.encoding import smart_str, uri_to_iri
from django.utils.translation import gettext_lazy as _
from rest_framework.fields import (
Field, empty, get_attribute, is_simple_callable, iter_options
Field, SkipField, empty, get_attribute, is_simple_callable, iter_options
)
from rest_framework.reverse import reverse
from rest_framework.settings import api_settings
@ -531,7 +531,30 @@ class ManyRelatedField(Field):
if hasattr(instance, 'pk') and instance.pk is None:
return []
relationship = get_attribute(instance, self.source_attrs)
try:
relationship = get_attribute(instance, self.source_attrs)
except (KeyError, AttributeError) as exc:
if self.default is not empty:
return self.get_default()
if self.allow_null:
return None
if not self.required:
raise SkipField()
msg = (
'Got {exc_type} when attempting to get a value for field '
'`{field}` on serializer `{serializer}`.\nThe serializer '
'field might be named incorrectly and not match '
'any attribute or key on the `{instance}` instance.\n'
'Original exception text was: {exc}.'.format(
exc_type=type(exc).__name__,
field=self.field_name,
serializer=self.parent.__class__.__name__,
instance=instance.__class__.__name__,
exc=exc
)
)
raise type(exc)(msg)
return relationship.all() if hasattr(relationship, 'all') else relationship
def to_representation(self, iterable):