Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make Django REST API accept a list

Tags:

python

django

I'm working on a functionality where I need to be able to post a list consisting of properties to the API. A property has a name, value and unit. Now I have two questions:

  1. How exactly should my list look for the API to accept it as a correct list from the get go? Should I parse the list as Objects? Or is a plain list fine?
  2. I am using the Django REST framework and I have made the API using this tutorial (works perfectly). But how do I make Django accept multiple objects/a list? I have read that it is as simple as adding many = True to where you instantiate the serializer, which I do here:

(for some reason the code won't format unless I put text here)

class PropertyViewSet(viewsets.ModelViewSet):  
    queryset = Property.objects.all()  
    serializer_class = PropertySerializer

So I tried doing serializer = PropertySerializer(queryset, many=True), which broke the API view. So I think I have to create a new serializer and view just for this (am I right)? But how do I make sure that my API knows which one to use at the right time?

If anyone could clarify this that would be great, thanks.

like image 568
Snackoverflow Avatar asked Feb 19 '18 16:02

Snackoverflow


2 Answers

If you need to create the object, here is how I did it:

# Mixin that allows to create multiple objects from lists.
class CreateListModelMixin(object):
    def get_serializer(self, *args, **kwargs):
        """ if an array is passed, set serializer to many """
        if isinstance(kwargs.get('data', {}), list):
            kwargs['many'] = True
        return super(CreateListModelMixin, self).get_serializer(*args, **kwargs)

And then in the view that you would like to use it in just do:

class PropertyCreateView(CreateListModelMixin, generics.CreateAPIView):
    serializer_class = PropertySerializer
    permission_classes = (IsAuthenticated, )

And that's already it (make sure to put in the mixin as an argument BEFORE the view; like I did it).

Now the body of your postrequest would look like this:

{
  [
    {
      "name": "<some_name>"
      "value": "<some_value>"
      "unit": "<some_unit>"
    },
    {
      "name": "<some_name>"
      "value": "<some_value>"
      "unit": "<some_unit>"
    },
    {
      "name": "<some_name>"
      "value": "<some_value>"
      "unit": "<some_unit>"
    },
    ...
  ]
}

The cool thing about it, this way you can also just post a single object like this:

{
  "name": "<some_name>"
  "value": "<some_value>"
  "unit": "<some_unit>"
}

I hope this helps! :)

like image 106
J. Hesters Avatar answered Oct 14 '22 04:10

J. Hesters


ModelViewSet class provides a create() method which only allows you to create one object at a time. see docs

if you want to POST a list of objects and insert each object to the database, you would have to create a custom view. for e.g.

from rest_framework.decorators import api_view
from django.shortcuts import redirect
from .models import MyModel

@api_view(['POST'])
def insert_list(request):
    if request.method == 'POST':
        for obj in request.POST['list']: #assuming you are posting a 'list' of objects
            MyModel.objects.create(name=obj.name, value=obj.value, unit=obj.unit)
    return redirect('url of MyObject List View')

to use your custom APIview alongside the viewset, just add your custom APIview to a different url not used by the viewset url e.g. if your viewset uses r'^myModel/$' then use r'^myModel/insert_list/$' for the createlist custom APIview

like image 40
Kevin L. Avatar answered Oct 14 '22 04:10

Kevin L.