0

There seems to be a lot of documentation out there on this but none of it seems to work for me. I am trying to build an API View that creates one or many objects at the same time.

Something like passing in the following:

[
    {
        "response": "I have no favourites",
        "user": 1,
        "update": "64c5fe6f-cb65-493d-8ef4-126db0195c33",
        "question": "297b46b4-714b-4434-b4e6-668ff926b38e"
    },
    {
        "response": "Good",
        "user": 1,
        "update": "64c5fe6f-cb65-493d-8ef4-126db0195c33",
        "question": "13916052-690e-4638-bb7c-908c38dcd75e"
    }
]

My current Viewset

class FeedbackViewSet(viewsets.ModelViewSet):

    permission_classes = [AllowAny]
    queryset = Feedback.objects.all()
    serializer_class = FeedbackSerializer

and Serializer:

class ContributionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Contribution
        fields = '__all__'

I have tried setting FeedbackSerializer(many=True) but this then tells me its not callable. Further, I have tried a ListCreateAPIView but this tells me it expects a dictionary but not a list.

NickP
  • 1,354
  • 1
  • 21
  • 51
  • Hello, does this help you ? https://stackoverflow.com/a/16697324/13964753 – Guillaume Apr 18 '21 at 17:27
  • Unfortunately I had already seen this. When I follow this approach - I get the error 'Expected a dictionary but got a list' – NickP Apr 18 '21 at 17:31
  • Maybe your are searching for a [bulk creation method](https://stackoverflow.com/questions/45917656/bulk-create-using-listserializer-of-django-rest-framework) ? – Romain Apr 18 '21 at 17:43

2 Answers2

1

Override the create(...) method

from rest_framework.response import Response
from rest_framework import status


class FeedbackViewSet(viewsets.ModelViewSet):
    permission_classes = [AllowAny]
    queryset = Feedback.objects.all()
    serializer_class = FeedbackSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, many=True) # not that `many=True` id mandatory since you are dealing with a list of of inputs
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(
            serializer.data,
            status=status.HTTP_201_CREATED,
            headers=headers
        )
JPG
  • 82,442
  • 19
  • 127
  • 206
1

you have the correct idea with many=True. You just need to put it in the correct location... so in the ViewSet:

class FeedbackViewSet(viewsets.ModelViewSet):

    permission_classes = [AllowAny]
    queryset = Feedback.objects.all()
    serializer_class = FeedbackSerializer

    def get_serializer(self, *args, **kwargs):
        # add many=True if the data is of type list
        if isinstance(kwargs.get("data", {}), list):
            kwargs["many"] = True

        return super(FeedbackViewSet, self).get_serializer(*args, **kwargs)

There are other ways to achieve the same behaviour, but I think this is pretty clean!

Ouss
  • 2,912
  • 2
  • 25
  • 45
  • Unfortunately seems to give me an error: 'ListSerializer' object is not iterable. It seemed to create the objects tho so guess the return is doing something odd. – NickP Apr 18 '21 at 19:04
  • I am looking into it – Ouss Apr 26 '21 at 15:52