Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST bulk post / post array of JSON objects

I have started to play around with the Django REST framework. So far I succeeded in creating a serializer for my object, creating the post view, post objects and return objects via Javascript's $.post(). So right now I have a proper conversion between my JSONs and Django model objects.

The problem is that I have an array of objects [A1, A2, ..., An]. Right now when I need to post such an array I do it object by object. Is there any possibility to post the whole array at once, and recover an array of objects inside my Django View? If so, what is the pattern to follow here? I guess I could define a new model which is an array of my current model, create a serializer for it, etc., but this does not seem too elegant.

Below are my view and serializer:

#serializers.py
class SearchRequestSerializer(serializers.ModelSerializer):

    def create(self):
        return SearchRequest(**self.validated_data)

    class Meta:
        model = SearchRequest



#views.py
@api_view(['POST'])
def post_calculation(request):
    if request.method == 'POST':

        #JSON to serializer object
        serializer = SearchRequestSerializer(data=request.data, many=False)
        if (serializer.is_valid() == False):
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        #create the Python object   
        search_request = serializer.create()

        #-- I do some processing stuff with the search_request object here ---

        #object back to JSON
        serializer3 = SearchRequestSerializer(search_request, many=False)
        return Response(serializer3.data) 
like image 388
Botond Avatar asked May 19 '16 17:05

Botond


1 Answers

There are two solutions to your problem:

The first solution is to override the .create() method of your view

By default, django rest framework assumes you are passing it a single object. To account for the possibility to pass it a list of objects you might rewrite it as follows:

def create(self, request, pk=None, company_pk=None, project_pk=None):
    is_many = isinstance(request.data, list)

    serializer = self.get_serializer(data=request.data, many=is_many)
    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)

Now your view will handle both single objects in POST data as well as a list of objects.

The second solution is to use a third party package

django-rest-framework-bulk provides the above functionality plus additional features (e.g. bulk update). You can check it out and decide whether it fits your needs.

Update: The solution for function based views

In order to get it to work with your function based view, the approach is similar:

@api_view(['POST'])
def post_calculation(request):
    if request.method == 'POST':
        is_many = isinstance(request.data, list)
        
        # JSON to serializer object
        serializer = SearchRequestSerializer(data=request.data, many=is_many)
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        serializer.save()
            
        #-- do some processing stuff here ---

        return Response(serializer.data) 

Do not call .create() method directly, use .save() instead. Also, when using many=False on serializer, the created instance is available under serializer.instance. I am not sure how to obtain the list of created instances though. You can try the same serializer.instance. If it doesn't work, try to find how to get it.

like image 139
iulian Avatar answered Oct 19 '22 19:10

iulian