使用 Django Rest Framework,如何上传文件并发送 JSON 有效负载?

2024-03-29

我正在尝试编写一个 Django Rest Framework API 处理程序,它可以接收文件以及 JSON 有效负载。我已将 MultiPartParser 设置为处理程序解析器。

然而,我似乎无法两者兼得。如果我将有效负载与文件一起作为多部分请求发送,则 JSON 有效负载可以在 request.data 中以损坏的方式使用(第一个文本部分直到第一个冒号作为键,其余的是数据)。我可以以标准形式参数发送参数,但我的 API 的其余部分接受 JSON 有效负载,并且我希望保持一致。 request.body 在引发时无法读取*** RawPostDataException: You cannot access body after reading from request's data stream

例如,请求正文中的文件和有效负载:
{"title":"Document Title", "description":"Doc Description"}
变成:
<QueryDict: {u'fileUpload': [<InMemoryUploadedFile: 20150504_115355.jpg (image/jpeg)>, <InMemoryUploadedFile: Front end lead.doc (application/msword)>], u'{%22title%22': [u'"Document Title", "description":"Doc Description"}']}>

有没有办法做到这一点?我可以吃掉蛋糕并保留它而不增加体重吗?

编辑: 有人建议这可能是一个副本Django REST Framework 上传图像:“提交的数据不是文件” https://stackoverflow.com/questions/28036404。它不是。上传和请求是分段完成的,请记住文件和上传都很好。我什至可以使用标准表单变量来完成请求。但我想看看是否可以在那里获取 JSON 有效负载。


对于需要上传文件并发送一些数据的人来说,没有直接的转发方式可以让它工作。有一个开放问题 https://github.com/json-api/json-api/issues/246在 json api 规范中。我见过的一种可能性是使用multipart/related如图所示here https://cloud.google.com/storage/docs/json_api/v1/how-tos/multipart-upload,但我认为在drf中实现它非常困难。

最后我实现的是将请求发送为formdata。您可以将每个文件发送为file以及所有其他数据作为文本。 现在,为了以文本形式发送数据,您可以使用一个名为data并将整个 json 作为值字符串发送。

模型.py

class Posts(models.Model):
    id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
    caption = models.TextField(max_length=1000)
    media = models.ImageField(blank=True, default="", upload_to="posts/")
    tags = models.ManyToManyField('Tags', related_name='posts')

serializers.py -> 不需要进行特殊更改,由于可写的 ManyToMany 字段实现,因此未在此处显示我的序列化器,因为它太长了。

views.py

class PostsViewset(viewsets.ModelViewSet):
    serializer_class = PostsSerializer
    parser_classes = (MultipartJsonParser, parsers.JSONParser)
    queryset = Posts.objects.all()
    lookup_field = 'id'

您将需要如下所示的自定义解析器来解析 json。

utils.py

from django.http import QueryDict
import json
from rest_framework import parsers

class MultipartJsonParser(parsers.MultiPartParser):

    def parse(self, stream, media_type=None, parser_context=None):
        result = super().parse(
            stream,
            media_type=media_type,
            parser_context=parser_context
        )
        data = {}
        # find the data field and parse it
        data = json.loads(result.data["data"])
        qdict = QueryDict('', mutable=True)
        qdict.update(data)
        return parsers.DataAndFiles(qdict, result.files)

The request example in postman case2

EDIT:

see this https://stackoverflow.com/a/50514022/3701807如果您想将每个数据作为键值对发送,则扩展答案

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Django Rest Framework,如何上传文件并发送 JSON 有效负载? 的相关文章

随机推荐