Django is a little bit annoying that it ignores relationship fields if depth = 1
One explicit way to deal with this is to define 2 serializers, and define which to use in your Viewset
views:
class MyViewSet(viewsets.ModelViewSet):
queryset = models.MyModel.objects.order_by("pk")
serializer_class = serializers.ExpandedSerializer
def get_serializer_class(self):
if self.action == ["list", "retrieve"]:
return serializers.MyExpandedSerializer
if self.action in ["create", "update", "partial_update"]:
return serializers.MyCreateSerializer
return super(LenderOfferingViewSet, self).get_serializer_class()
def create(self, request, *args, **kwargs):
"""Overload the create method with a different response serializer."""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
response_serializer = serializers.MyExpandedSerializer(serializer.instance)
return Response(response_serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def update(self, request, *args, **kwargs):
"""Overload method for PUT/PATCH to correctly set values and set response serializer."""
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
response_serializer = serializers.MyExpandedSerializer(serializer.instance)
return Response(response_serializer.data)
And then serializers:
class MyCreateSerializer(serializers.ModelSerializer):
class Meta:
model = models.MyObject
fields = ["issue_name", "status"]
depth = 0 # no expansion else create/update fail on missing fields (serializer ignores related fields)
class MyExpandedSerializer(serializers.ModelSerializer):
"""This serializer expands related fields explicitly with SerializerMethodFields."""
class Meta:
model = models.My
fields = ["id", "issue_name", "status"]
depth = 1
Then, when you
POST /my_endpoint/
{
issue_name: 'This is a problem',
status: 3
}
You will get the response (on i.e. /my_endpoint/1)
{
id: 1,
issue_name: 'This is a problem',
status: {
id: 3,
name: 'todo'
}
}