Skip to content

Commit

Permalink
bugfix SlugRelatedField with a model property target #943
Browse files Browse the repository at this point in the history
  • Loading branch information
tfranzel committed Feb 21, 2023
1 parent 7392ba9 commit 21068e0
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
9 changes: 8 additions & 1 deletion drf_spectacular/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,16 @@ def _map_serializer_field(self, field, direction, bypass_extensions=False):
# be graceful and default to string.
model_field = follow_field_source(model, source, default=models.TextField())

# Special case: SlugRelatedField also allows to point to a callable @property.
if callable(model_field):
schema = self._map_response_type_hint(model_field)
elif isinstance(model_field, models.Field):
schema = self._map_model_field(model_field, direction)
else:
assert False, f'Field "{field.field_name}" must point to either a property or a model field.'

# primary keys are usually non-editable (readOnly=True) and map_model_field correctly
# signals that attribute. however this does not apply in the context of relations.
schema = self._map_model_field(model_field, direction)
schema.pop('readOnly', None)
return append_meta(schema, meta)

Expand Down
28 changes: 28 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3008,3 +3008,31 @@ class XViewset(viewsets.ModelViewSet):
'default': []
}
}


def test_slug_related_field_to_model_property(no_warnings):
class M10(models.Model):
@property
def property_field(self) -> float:
return 42

class M11(models.Model):
field = models.ForeignKey(M10, on_delete=models.CASCADE)

class XSerializer(serializers.ModelSerializer):
# How the field is defined in a Serializer
field = serializers.SlugRelatedField(slug_field="property_field", read_only=True)

class Meta:
fields = '__all__'
model = M11

class XViewset(viewsets.ModelViewSet):
serializer_class = XSerializer
queryset = M11.objects.all()

schema = generate_schema('/x', XViewset)
assert schema['components']['schemas']['X']['properties'] == {
'id': {'type': 'integer', 'readOnly': True},
'field': {'format': 'double', 'readOnly': True, 'type': 'number'}
}

0 comments on commit 21068e0

Please sign in to comment.