Django Rest Framework 同时传文件和JSON时request.data无法获取request.body中存在的数据
问题成因
- 编码格式冲突:HTTP协议中上传二进制文件必须使用
multipart/form-data编码,而json参数对应的application/json编码无法承载二进制文件,两者不能在同一个请求中混用。 - requests库逻辑限制:当
requests.post同时传入files和json参数时,requests会优先采用multipart/form-data编码,直接忽略传入的json参数,你放在json里的普通参数不会被识别为表单字段。 - DRF解析逻辑匹配:DRF会根据请求头的
Content-Type选择对应解析器,当请求为multipart/form-data时,会使用MultiPartParser解析,只会提取表单中的文件和普通字段,不会解析整个请求体的JSON内容,因此你存在请求体里的JSON参数无法被request.data识别。
解决方法
1. 请求侧核心修改
移除json参数,将所有普通参数直接放到data参数中传递,requests会自动将这些参数打包到multipart/form-data的普通字段中,修改后代码示例:
j=[i.json() for i in AttachmentType.objects.annotate(text_len=Length('terms')).filter(text_len__gt=1)] j = json.dumps(j) url = settings.WEBSERVICE_URL + '/api/v1/inference' headers = { 'Content-Disposition': f'attachment; filename={file_name}', 'callback': 'http://localhost', 'x-api-key': settings.WEBSERVICE_API_KEY } # 普通参数直接放在data中传递 data = { 'type':j } files = { 'file':file } # 移除json参数,仅传递data和files response = requests.post( url, headers=headers, files=files, data=data, )
2. DRF侧逻辑优化
修改后直接通过request.data即可获取到type参数,不需要额外做引号替换处理:
class InferenceView(APIView): """ From a pdf file, extract infos and return it """ permission_classes = [HasAPIKey] def post(self, request): callback = request.headers.get('callback', None) # check correctness of callback msg, ok = check_callback(callback) if not ok: # if not ok return bad request return build_json_response(msg, 400) # 直接获取文件和普通参数即可 zip_file = request.FILES.get('file', None) type_str = request.data.get('type', None) parsed = json.loads(type_str) if type_str else None
补充说明:DRF默认已配置
MultiPartParser解析器,无需额外修改配置,如果出现仍无法获取参数的情况,可检查settings.py中DEFAULT_PARSER_CLASSES配置是否包含rest_framework.parsers.MultiPartParser。
内容的提问来源于stack exchange,提问作者Filippo
相关产品推荐
相关产品推荐

