2

How can I serialize multiple InMemoryUploadedFile using serializers.ListField() ??


code snippet

#views.py
@api_view(['POST', 'GET'])
def create_post(request):
    if request.method == 'POST':
        altered_request_data = request.data.copy()
        in_memory_upload_files_list = [value for value in request.FILES.values()]
        altered_request_data['files'] = in_memory_upload_files_list
        serializer = PostSerializer(data=altered_request_data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(data=serializer.data, status=201)
    else:
        qs = Post.objects.all()
        serializer = PostSerializer(qs, many=True)
        return Response(serializer.data)

#serilizers.py
class PostSerializer(serializers.ModelSerializer):
    files = serializers.ListField(child=serializers.FileField(), write_only=True)

    class Meta:
        fields = '__all__'
        model = Post

current response

{
    "files": {
        "0": [
            "The submitted data was not a file. Check the encoding type on the form."
        ]
    }
}
2
  • i think you does not need it, because you call save just process the files in the save and all be fine. Commented Apr 25, 2019 at 8:54
  • the given response is the validation error and it raised before calling the save() method Commented Apr 25, 2019 at 9:00

2 Answers 2

1

The issue was lies in this line,

altered_request_data['files'] = in_memory_upload_files_list

here the altered_request_data is a QueryDict object, so if we assign anything to it will call the __setitem__() method

In [6]: from django.http import QueryDict                                                                                                                                                                          

In [7]: qd = QueryDict('a=1&a=2&c=3',mutable=True)                                                                                                                                                                 

In [8]: qd                                                                                                                                                                                                         
Out[8]: <QueryDict: {'a': ['1', '2'], 'c': ['3']}>

In [9]: my_list = [i for i in range(10)]                                                                                                                                                                           

In [10]: my_list                                                                                                                                                                                                   
Out[10]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [11]: qd['foo']=my_list                                                                                                                                                                                         

In [12]: qd                                                                                                                                                                                                        
Out[12]: <QueryDict: {'a': ['1', '2'], 'c': ['3'], 'foo': [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]}>

See that? qd['foo'] become a list of list. That is, anything assigning to a QueryDict will be stored inside a list object.

So, what's the solution??

QueryDict class has a method QueryDict.setlist will do the job

In [15]: qd__new                                                                                                                                                                                                   
Out[15]: 

In [16]: qd__new = QueryDict('a=1&a=2&c=3',mutable=True)                                                                                                                                                           

In [17]: qd__new                                                                                                                                                                                                   
Out[17]: <QueryDict: {'a': ['1', '2'], 'c': ['3']}>

In [18]: my_list                                                                                                                                                                                                   
Out[18]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [19]: qd__new.setlist('foo_new',my_list)                                                                                                                                                                        

In [20]: qd__new                                                                                                                                                                                                   
Out[20]: <QueryDict: {'a': ['1', '2'], 'c': ['3'], 'foo_new': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}>

code snippet

views.py

@api_view(['POST', 'GET'])
def create_post(request):
    if request.method == 'POST':
        altered_request_data = request.data.copy()
        in_memory_upload_files_list = [value for value in request.FILES.dict().values()]

        altered_request_data.setlist('files', in_memory_upload_files_list)

        serializer = PostSerializer(data=altered_request_data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(data=serializer.data, status=201)
    else:
        qs = Post.objects.all()
        serializer = PostSerializer(qs, many=True)
        return Response(serializer.data)
Sign up to request clarification or add additional context in comments.

Comments

0

You should use getlist method of FILES that will give you List of Files.

in_memory_upload_files_list = request.FILES.getlist('<file field name>')
altered_request_data['files'] = in_memory_upload_files_list
serializer = PostSerializer(data=altered_request_data)

Here <file field name> will be name file field on which you upload file.

https://docs.djangoproject.com/en/2.2/ref/request-response/#django.http.QueryDict.getlist

7 Comments

I'm uploading the files as this - screenshot and I am not interested to specify the names in getlist() method, because I'm uploading multiple files
you are using key "file" just put "file" replace in <file field name> In you snapshot you mentioned file_1, file_2 means postman uploading images based on "file" field name.
Without key you can't get anything for FILES, POST and GET. you will always get dictionary in these method. so that always need keys to access it
What if I want to upload n number of files? and the DRF side is not aware of which key (such as file_1,file_2,file_3 ..etc)is used to send those n files. That's why I used the .values() method
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.