Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework cannot deal with multiple objects in model viewset

I have a very simple model and its related serializer and views:

class Page(models.Model):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=255)
    pub_date = models.DateTimeField(default=timezone.now)

class PageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Page
        fields = ('user', 'title', 'pub_date')

class PageViewSet(viewsets.ModelViewSet):
    queryset = Page.objects.all()
    serializer_class = PageSerializer

Now I can post like this:

{
    "user": 1,
    "title": "Lorem ipsum"
}

This works fine. But I would like to post multiple objects like this:

[
    {
        "user": 1,
        "title": "Lorem ipsum one"
    },
    {
        "user": 1,
        "title": "Lorem ipsum two"
    }
]

But this gives me an error:

"non_field_errors": [

"Invalid data. Expected a dictionary, but got list."

]

So to accept multiple objects I modified the view as per the doc:

class PageViewSet(viewsets.ModelViewSet):
    queryset = Page.objects.all()
    serializer_class = PageSerializer(queryset, many=True)

But I am getting an error:

TypeError at /api/blog/pages/

'ListSerializer' object is not callable

What am I missing here?

like image 300
Robin Avatar asked Apr 20 '17 17:04

Robin


People also ask

What is ViewSet in Django REST framework?

A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as . get() or . post() , and instead provides actions such as . list() and . create() .

How do I create multiple model instances with Django REST framework?

To create multiple model instances with the Python Django Rest Framework, we can create a serialize with many set to True . to call the super class' __init__ method with the many argument set to many . If it's True , then our serializer can accept multiple model instances.

What is difference between Api_view and ViewSet?

APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.

What is QuerySet in Django REST framework?

The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects. The default behavior of REST framework's generic list views is to return the entire queryset for a model manager.


1 Answers

You had it set up correctly before, the serializer_class should point to the class like this:

serializer_class = PageSerializer

You were right on the error, it doesn't like receiving multiple objects in the POST. One way to fix it would be to override the get_serializer method n the view, adding in many=True there.

Something like:

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

        # check if many is required
        if isinstance(data, list):
            kwargs["many"] = True

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

To answer your question in the comments: isinstance() is a Python method to check the type of an object. In this case, it's a list when passing in multiple objects, so we just check what type data is and set many=true if it's a list.

DRF docs regarding get_serializer (under methods)

Python docs regarding isinstance

like image 103
Cody Parker Avatar answered Nov 15 '22 08:11

Cody Parker