Django Rest Framework Batch Create

2020-02-28 05:30发布

问题:

I'm trying to make an api where you can create multiple objects with a single Post request using django rest framework. However, my serializer is providing an error which I don't understand. First off here's the a skeleton of my code

My Serializer:

class MyModelSerializer(serializers.ModelSerializer):
# override the constructor to always use the many flag
def __init__(self, *args, **kwargs):
    many = kwargs.pop('many', True)
    super(MyModelSerializer, self).__init__(many=many, *args, **kwargs)

class Meta:
    model = MyModel
    fields = ('field1', 'field2')

My List View

class MyModelListView(generics.ListCreateAPIView):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

    def post(self, request, *args, **kwargs):
        if request.DATA['batch']:
            json = request.DATA['batchData']
            stream = StringIO(json)
            data = JSONParser().parse(stream)
            request._data = data
        return super(CharacterDatumList, self).post(request, *args, **kwargs)

My ajax call

$.ajax({
    type: "POST",
    url: '/characterDatum/',
    data: {
        'batch' : true,
        'batchData' : '[{"field1": "x", "field2": "y", },{"field1": "a", "field2": "b"}]'
    },
    success: function(response) {
        console.log('success');
    },
    datatype: 'json'
});

However, in the django rest framework I get a serialization validation error at the line below

class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
        if serializer.is_valid(): # returns not valid

Does anyone know why this might be the case?

回答1:

I found it! The serializer was not actually using the many option so I had to override the get_serializer method in MyModelListView

def get_serializer(self, instance=None, data=None,
                        files=None, many=True, partial=False):
        return super(MyModelListView, self).get_serializer(instance, data, files, many, partial)


回答2:

Here is what worked for me. I had to iterate over the list of items.

class ProportionViewSet(viewsets.ModelViewSet):
    queryset = Proportion.objects.all()
    serializer_class = ProportionSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)

        ###
        # First we need to iterate over the list o items
        ###

        for single_proportion in serializer.validated_data:
            # Try to get proportion from database for selected user
            try:
                proportions = Proportion.objects.get(user=self.request.user, category=single_proportion['category']['id'])
                proportions.some_property = "New value"
                proportions.save()
            # If it is not in the model, then we should create it
            except Proportion.DoesNotExist:
                proportion = Proportion(
                    category=Category.objects.get(id=single_proportion['category']['id']),
                    proportion_in_clicks=single_proportion['proportion_in_clicks'],
                    user=single_proportion['user']
                )
                proportion.save()