petroleyum petroleyum - 2 months ago 7x
Python Question

How to post/put json data to ListSerializer

I'm reading about customizing multiple update here and I haven't figured out in what case the custom

update method is called. I would like to update multiple objects at once, I'm not worried about multiple create or delete at the moment.

From the example in the docs:

class BookListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
# custom update logic

class BookSerializer(serializers.Serializer):
class Meta:
list_serializer_class = BookListSerializer

And my ViewSet

class BookViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer

And my url setup using

router = routers.DefaultRouter()
router.register(r'Book', BookViewSet)

urlpatterns = patterns('',
url(r'^api/', include(router.urls)),

So I have this set up using the
so that
will use the

Is the general idea that if I POST/PUT/PATCH an array of JSON objects to
then the serializer should switch over to

I've tried POST/PUT/PATCH JSON data list to this
that looks like:

[ {id:1,title:thing1}, {id:2, title:thing2} ]

but it seems to still treat the data using
instead of
. If I submit via POST I get
Invalid data. Expected a dictionary, but got list
. and if I submit via PATCH or PUT then I get a
Method 'PATCH' not allowed

Do I have to adjust the
of the
or the
to allow POST/PATCH/PUT of lists? Are the generic views not set up to work with the

I know I could write my own list deserializer for this, but I'm trying to stay up to date with the new features in DRF 3 and it looks like this should work but I'm just missing some convention or some option.


Django REST framework by default assumes that you are not dealing with bulk data creation, updates, or deletion. This is because 99% of people are not dealing with bulk data creation, and DRF leaves the other 1% to third-party libraries.

In Django REST framework 2.x and 3.x, a third party package exists for this.

Now, you are trying to do bulk creation but you are getting an error back that says

Invalid data. Expected a dictionary, but got list

This is because you are sending in a list of objects to create, instead of just sending in one. You can get around this a few ways, but the easiest is to just override get_serializer on your view to add the many=True flag to the serializer when it is a list.

def get_serializer(self, *args, **kwargs):
    if "data" in kwargs:
        data = kwargs["data"]

        if isinstance(data, list):
            kwargs["many"] = True

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

This will allow Django REST framework to know to automatically use the ListSerializer when creating objects in bulk. Now, for other operations such as updating and deleting, you are going to need to override the default routes. I'm going to assume that you are using the routes provided by Django REST framework bulk, but you are free to use whatever method names you want.

You are going to need to add methods for bulk PUT and PATCH to the view as well.

from rest_framework.response import Response

def bulk_update(self, request, *args, **kwargs):
    partial = kwargs.pop("partial", False)

    queryset = self.filter_queryset(self.get_queryset))

    serializer = self.get_serializer(instance=queryset,, many=True)


    return Response(

def partial_bulk_update(self, *args, **kwargs):
    kargs["partial"] = True
    return super(MyView, self).bulk_update(*args, **kwargs)

This won't work out of the box as Django REST framework doesn't support bulk updates by default. This means you also have to implement your own bulk updates. The current code will handle bulk updates as though you are trying to update the entire list, which is how the old bulk updating package previously worked.

While you didn't ask for bulk deletion, that wouldn't be particularly difficult to do.

def bulk_delete(self, request, *args, **kwargs):
    queryset = self.filter_queryset(self.get_queryset())
    return Response(status=204)

This has the same effect of removing all objects, the same as the old bulk plugin.

None of this code was tested. If it doesn't work, consider it as a detailed example.