Skip to content

Silent skipping of read-only fields that throw exceptions: weird! unintentional? #2598

Closed
@ezheidtmann

Description

@ezheidtmann

I have a serializer with some read-only fields which are populated by a method on the model. This worked great. Then I made a change elsewhere that broke my method. Now my fields don't show up. Instead, I would have expected the exception to reach the browser somehow -- a 500 error from DRF or from Django core.

I discovered that DRF is swallowing the exception thrown inside my function (an AttributeError) and silently skipping the field. This is confusing to me and I don't understand how this is useful; in fact, it seems that the logic is appropriate for a de-serialization (i.e. create or update) but not for output.

If the current behavior is desired, what's the reasoning? And if so, can we add something to the guide about it, under exception handling?

For context, here's my serializer:

class SectionSerializer(serializers.HyperlinkedModelSerializer):
    route_count = serializers.IntegerField(source='get_route_count', read_only=True)

And here's the method on my model:

class Section(Versionable):
    ...
    def get_route_count(self):
        if self.route_type == Section.RT_BOULDER:
            return self.boulderroute_set.count()
        elif self.route_type == Section.RT_SPORT:
            return self.sportroute_set.count()

(My function get_route_count is broken because I removed the .RT_* constants in a refactor)

And this is where my AttributeError is caught in fields.py:

class Field(object):
    ...
    def get_attribute(self, instance):
        """
        Given the *outgoing* object instance, return the primitive value
        that should be used for this field.
        """
        try:
            return get_attribute(instance, self.source_attrs)
        except (KeyError, AttributeError) as exc:
            if not self.required and self.default is empty:
                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)

Thanks all!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions