Home > Software design >  How to send several fields in the response with a PUT request?
How to send several fields in the response with a PUT request?

Time:05-19

I would like when my PUT request is successful it returns me a response with all the fields in my PlantSerializer because currently the response returns me this:

{
   "id":48,
   "name":"Jar",
   "width":"50",
   "height":"50",
   "exposure":"None",
   "qr_code":"",
   "garden":65,
   "plant":[
      7
   ]
}

But, I would like the response to return this instead:

{
   "id":48,
   "name":"Jar",
   "width":"50",
   "height":"50",
   "exposure":"None",
   "qr_code":"",
   "garden":65,
   "plant":[
      "id":7,
      "name":"Artichoke",
      "image":null
   ]
}

How can I achieve this result?

Here is my serializers and my model class :

class Plot(models.Model):

    name = models.CharField(max_length=50)
    garden = models.ForeignKey('perma_gardens.Garden', on_delete=models.CASCADE)
    width = models.CharField(max_length=50, blank=True, null=True)
    height = models.CharField(max_length=50, blank=True, null=True)
    plant = models.ManyToManyField('perma_plants.Plant', related_name='%(class)s_plant', blank=True)

# Here is my serializers :
class GardenSerializer(serializers.ModelSerializer):
    class Meta:
        model = Garden
        fields = ('id', 'name',)

class PlantSerializer(serializers.ModelSerializer):
    class Meta:
        model = Plant
        fields = ('id', 'name', 'image')


class ReadPlotSerializer(serializers.ModelSerializer):
    garden = GardenSerializer(required=True)
    plant = PlantSerializer(many=True)
    id = serializers.IntegerField(read_only=True)

    class Meta:
        model = Plot
        fields = '__all__'
        read_only_fields = [fields]


class WritePlotSerializer(serializers.ModelSerializer):
    class Meta:
        model = Plot
        fields = '__all__'

And here is my views :

class PlotViewSet(viewsets.ModelViewSet):
    queryset = Plot.objects.all()

    def create(self, request, *args, **kwargs):
        serializer = WritePlotSerializer(data=request.data, many=isinstance(request.data, list))
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    def partial_update(self, request, *args, **kwargs):
        instance = self.queryset.get(pk=kwargs.get('pk'))
        serializer = WritePlotSerializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

    def get_serializer_class(self):
        if self.action in ("list", "retrieve"):
            return ReadPlotSerializer
        return WritePlotSerializer

CodePudding user response:

In the fuction partial_update you are utilizing the WritePlotSerializer, which only has the plant field implicitly through the fields=__all__ value. This is probably causing drf to use a PrimaryKeyRelatedField, and as such you don't get all the extra fields you defined in your PlantSerializer.

If I understand correctyl you want to use the WritePlotSerializer in the update but use the ReadPlotSerializer when returning the object. You probably should combine both of them in a single serializer by overriding the update method in order to support updating the nested Plant objects. Here is the related documentation.

Alternatively, if you don't want to update the Plants values you can use a slightly modified version of the ReadPlotSerializer in all calls:


class PlotSerializer(serializers.ModelSerializer):
    garden = GardenSerializer(required=True, read_only=True)
    plant = PlantSerializer(many=True, read_only=True)
    id = serializers.IntegerField(read_only=True)

    class Meta:
        model = Plot
        fields = '__all__'
  • Related