drf-yasg icon indicating copy to clipboard operation
drf-yasg copied to clipboard

Exception when using SlugRelatedField(many=True, default=list)

Open franciscouzo opened this issue 5 years ago • 1 comments

When using the following serializer:

class ObjectSerializer(serializers.ModelSerializer):
   m2m_field = serializers.SlugRelatedField(
       queryset=Field.objects.all(), many=True, slug_field='code',
       source='m2m', write_only=True, default=list
   )

When the schema generator is run, I get the following exception:

'default' on schema for SlugRelatedField(default=<class 'list'>, queryset=<QuerySet [<Field: Field object (1)>]>, slug_field='code', source='m2m', write_only=True) will not be set because to_representation raised an exception
Traceback (most recent call last):
  File "venv/lib/python3.7/site-packages/drf_yasg/utils.py", line 484, in get_field_default
    default = field_value_to_representation(field, default)
  File "venv/lib/python3.7/site-packages/drf_yasg/utils.py", line 451, in field_value_to_representation
    value = field.to_representation(value)
  File "venv/lib/python3.7/site-packages/rest_framework/relations.py", line 460, in to_representation
    return getattr(obj, self.slug_field)
AttributeError: 'list' object has no attribute 'code'

I can prevent the exception if I use ManyRelatedField directly, but the documentation says not to use it.

franciscouzo avatar Sep 04 '19 13:09 franciscouzo

I get the same issue in a normal Serializer, it attempts to find the serializer fields in the empty list since it's the default value

class ChildSerializer(serializers.Serializer):
    something = serializers.CharField()

class ParentSerializer(serializers.Serializer):
    value = ChildSerializer(many=True, default=[])

returns:

Traceback (most recent call last):
  File ".../venv/lib/python3.6/site-packages/drf_yasg/utils.py", line 497, in get_field_default
    default = field_value_to_representation(field, default)
  File ".../venv/lib/python3.6/site-packages/drf_yasg/utils.py", line 461, in field_value_to_representation
    value = field.to_representation(value)
  File ".../venv/lib/python3.6/site-packages/rest_framework/serializers.py", line 502, in to_representation
    attribute = field.get_attribute(instance)
  File ".../venv/lib/python3.6/site-packages/rest_framework/fields.py", line 490, in get_attribute
    raise type(exc)(msg)
AttributeError: Got AttributeError when attempting to get a value for field `something` on serializer `ChildSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `list` instance.
Original exception text was: 'list' object has no attribute 'something'.

I guess many=True with default=list should be taken into account in utils:get_field_default() maybe something like the following?

in https://github.com/axnsan12/drf-yasg/blob/1.20.0/src/drf_yasg/utils.py#L495

...
many = getattr(field, 'many', False)
if default is not serializers.empty and default is not None and not (many is True and default in [list, []]):
    try:
        default = field_value_to_representation(field, default)
...

I'm not aware of the effects this might have so it's just an initial idea :)

sacha-c avatar Jul 20 '21 12:07 sacha-c