【问题标题】:Serialize multiple InMemoryUploadedFile using ListField : Django REST Framework使用 ListField 序列化多个 InMemoryUploadedFile:Django REST Framework
【发布时间】:2019-04-25 18:17:20
【问题描述】:

如何使用serializers.ListField() 序列化多个InMemoryUploadedFile??


代码 sn-p

#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

当前反应

{
    "files": {
        "0": [
            "The submitted data was not a file. Check the encoding type on the form."
        ]
    }
}

【问题讨论】:

  • 我认为您不需要它,因为您调用save 只需处理保存中的文件就可以了。
  • 给定的响应是验证错误,它在调用save() 方法之前引发

标签: python django django-rest-framework django-serializer django-uploads


【解决方案1】:

问题出在这一行,

altered_request_data['files'] = in_memory_upload_files_list

这里的 altered_request_data 是一个QueryDict 对象,所以如果我们给它分配任何东西都会调用__setitem__() 方法

In [6]: from django.http import QueryDict                                                                                                                                                                          

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

In [8]: qd                                                                                                                                                                                                         
Out[8]: &ltQueryDict: {'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]: &ltQueryDict: {'a': ['1', '2'], 'c': ['3'], 'foo': [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]}>

看到了吗? qd['foo'] 成为列表列表。也就是说,任何分配给 QueryDict 的内容都将存储在 list 对象中。

那么,解决办法是什么??

QueryDict 类有一个方法 QueryDict.setlist 可以完成这项工作

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]: &ltQueryDict: {'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]: &ltQueryDict: {'a': ['1', '2'], 'c': ['3'], 'foo_new': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}>

代码 sn-p

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)

【讨论】:

    【解决方案2】:

    您应该使用FILESgetlist 方法,它会为您提供文件列表。

    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)
    

    此处&lt;file field name&gt; 将是您上传文件的名称文件字段。

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

    【讨论】:

    • 我正在上传这些文件 - screenshot,我不想在 getlist() 方法中指定名称,因为我正在上传多个文件
    • 您正在使用“文件”键,只需将“文件”替换在 在您提到文件_1 的快照中,文件_2 表示邮递员根据“文件”字段名称上传图像。
    • 如果没有密钥,您将无法获取 FILES、POST 和 GET 的任何内容。您将始终在这些方法中获得字典。所以总是需要密钥才能访问它
    • 如果我想上传 n 个文件怎么办?并且 DRF 端不知道使用哪个key(例如file_1file_2file_3 ..etc)来发送那些n 文件。这就是我使用 .values() 方法的原因
    猜你喜欢
    • 2022-12-03
    • 1970-01-01
    • 1970-01-01
    • 2016-12-17
    • 1970-01-01
    • 2014-04-13
    • 2018-02-17
    • 2014-11-12
    • 1970-01-01
    相关资源
    最近更新 更多