2

I am trying to use a ListSerializer so that I can create/de-serialize multiple objects in a list on a POST. I followed the guide at https://www.django-rest-framework.org/api-guide/serializers/#listserializer but seem to be running into this error when i visit the endpoint.

assert self.child is not None, '``child`` is a required argument.'

python3.7/site-packages/rest_framework/serializers.py in __init__, line 592

My serializers are as follows:

class PredictionListSerializer(serializers.ListSerializer):

    def update(self, instance, validated_data):
        pass

    def create(self, validated_data):
        predictions = [Prediction(**item) for item in validated_data]
        return Prediction.objects.bulk_create(predictions)
class NestedPredictionSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    # Nested Serializer
    data = DataSerializer()

    class Meta:
        model = Prediction
        list_serializer_class = PredictionListSerializer
        fields = ('id', 'specimen_id', 'data' 'date_added',)
        extra_kwargs = {
            'slug': {'validators': []},
        }
        datatables_always_serialize = ('id',)

The assertion error is being thrown in the initialization of the ListSerializer, however, the serializer is being initialized in a ViewSet like so.

class BulkPredictionViewSet(viewsets.ModelViewSet):
    queryset = Prediction.objects.all()
    serializer_class = PredictionListSerializer

Anyone familiar with this issue? I am wondering if my lack o control around initialization of the serializer (because I am using a ViewSet) is affecting this. If I try to pass the NestedPredictionSerializer into the ViewSet I get "Invalid data. Expected a dictionary, but got list."

EDIT:

I was able to overwrite the get_serializer method in my ViewSet to set many=True and pass the serializer as my NestedPredictionSerializer which recognizes the list on a POST. Howeber, on a get now I receive the error When a serializer is passed a ``data`` keyword argument you must call ``.is_valid()`` before attempting to access the serialized ``.data`` representation. You should either call ``.is_valid()`` first, or access ``.initial_data`` instead.

RubyJ
  • 193
  • 2
  • 16

2 Answers2

2

I was able to get both the POST and GET working when the following the advice on this read combined with this answer: https://stackoverflow.com/a/45651309/3439441

My overridden ViewSet.get_serializer now looks like this:

    def get_serializer(self, *args, **kwargs):
        if self.request.method.lower() == 'post':
            data = kwargs.get('data')
            kwargs['many'] = isinstance(data, list)
        return super(BulkPredictionViewSet, self).get_serializer(*args, **kwargs)
RubyJ
  • 193
  • 2
  • 16
1

Just use many=True only for create action:

class BulkPredictionViewSet(viewsets.ModelViewSet):
    queryset = Prediction.objects.all()
    serializer_class = NestedPredictionSerializer

    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs['context'] = self.get_serializer_context()
        if self.action == 'create': 
            kwargs['many'] = True
        return serializer_class(*args, **kwargs)

You don't need to use PredictionListSerializer since many=True will create ListSerializer automatically.

Julio Marins
  • 10,039
  • 8
  • 48
  • 54
neverwalkaloner
  • 46,181
  • 7
  • 92
  • 100
  • 1
    When I do this, the POST works as expected, however when I try to perform a GET on the same endpoint I get ```AttributeError: 'PredictionListSerializer' object has no attribute 'fields'``` So, I tried to set ```many = False``` in an else case but that raises another Error about a specific field. – RubyJ Jan 23 '19 at 17:07
  • When I add an else ```many=False``` case: ```Got AttributeError when attempting to get a value for field `specimen_id` on serializer `NestedPredictionSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `list` instance. Original exception text was: 'list' object has no attribute 'specimen_id'.``` – RubyJ Jan 23 '19 at 17:13
  • @RubyJ you need to remove `list_serializer_class = PredictionListSerializer` line from `NestedPredictionSerializer` class. If this not helps add full traceback to your question. – neverwalkaloner Jan 23 '19 at 17:16
  • I don't understand what you mean. I removed that line and I still get the same error. If I remove the overridden `get_serializer` method then I do not get an Exception on the GET, but then the POST does not work as in the original question. – RubyJ Jan 23 '19 at 17:55
  • I have even gone as far to as remove the entire `PredictionListSerializer` code. When I override `get_serializer` as you descirbed, the GET request runs into the same error `AttributeError: 'ListSerializer' object has no attribute 'fields'` – RubyJ Jan 23 '19 at 18:00
  • any more suggestions? – RubyJ Jan 23 '19 at 18:27