【问题标题】:Django - post InMemoryUploadedFile to external REST apiDjango - 将 InMemoryUploadedFile 发布到外部 REST api
【发布时间】:2019-12-04 15:32:13
【问题描述】:

在 Django Rest 框架中,我想在收到文件后立即将作为 InMemoryUploadedFile 接收的文件发布到不同的服务器。

听起来很简单,但request.post() 函数似乎无法正确发送此类文件:

def post(self, request, *args, **kwargs):
    data = request.data
    print(data)
    # <QueryDict: {'file': [<InMemoryUploadedFile: myfile.pdf (application/pdf)>]}>
    endpoint = OTHER_API_URL + "/endpoint"
    r = requests.post(endpoint, files=data)

我的另一台服务器(通过flask)收到带有文件名的请求,但不是内容:

@app.route("/endpoint", methods=["POST"])
def endpoint():
    if flask.request.method == "POST":
        # I removed the many checks to simplify the code
        file = flask.request.files['file']
        path = os.path.join(UPLOAD_FOLDER, file.filename)
        file.save(path)        

        print(file) #<FileStorage: u'file.pdf' (None)>
        print(os.path.getsize(path)) #0

        return [{"response":"ok"}]

当使用邮递员在表单数据中直接将文件发布到该 api 时,它按预期工作:

        print(file) # <FileStorage: u'file.pdf' ('application/pdf')>
        print(os.path.getsize(path)) #8541

有关如何解决此问题的任何帮助,即将InMemoryUploadedFile 类型转换为普通 REST api 可以理解的内容?或者只是添加正确的标题?

【问题讨论】:

  • 能否包含相关的 Flask 视图,以查看文件在接收端是如何处理的?
  • 它包含 self.request.FILES
  • @kristaps 我用细节编辑了这个问题。
  • 两台服务器之间是否有任何代理,可能会改变对 Flask 服务器的请求?
  • 不,两台服务器是两个独立的docker容器

标签: python django django-rest-framework


【解决方案1】:

我必须在 Python 3 中解决将上传的文件从 Django 前端网站传递到 Django 后端 API 的问题。可以通过对象的 .file 属性的 .getvalue() 方法访问 InMemoryUploadedFile 的实际文件数据。

        path="path/to/api"
        in_memory_uploaded_file = request.FILES['my_file']
        io_file = in_memory_uploaded_file.file
        file_value = io_file.getvalue()
        files = {'my_file': file_value}
        make_http_request(path, files=files)

并且可以缩短

        file = request.FILES['my_file'].file.getvalue()
        files = {'my_file': file}

在此之前,尝试发送 InMemoryUploadFile 对象、文件属性或 read() 方法的结果都证明在到达 API 时发送的是空白/空文件。

【讨论】:

  • 我尝试了以下代码。但对我不起作用。
  • view.py- kyc_file = request.FILES['kyc_doc'].file.getvalue() files = {"kyc_doc":kyc_file} resp = accService.publishKY(data,files) -------- Service.py -- def publishKY(self,data,files): curl = CurlWrapper() response_kcloud = curl.post(endpoint,data,{ "api-key":acc.api_key,"Content-Type":"multipart/form-data"},files) ------ class CurlWrapper(): def post(self,url,data,headers,ufile=None): if ufile is None: return requests.post(url, data=json.dumps(data), headers=headers) else: return requests.post(url, data=data, headers=curlheaders,files=ufile)
【解决方案2】:

我有同样的问题和同样的情况。 我的工作解决方案

    headers = {
        "Host": API_HOST,
        "cache-control": "no-cache",
    }

    try:
        data = json_request = request.POST['json_request'].strip()
        data = json.loads(data) # important!
    except:
        raise Http404

    try:
        in_memory_uploaded_file = request.FILES['file'].file.getvalue() 
        files = {'photo': in_memory_uploaded_file} # important!
    except:
        files = {}

    if USE_HTTPS:
        API_HOST = f'https://{API_HOST}'
    else:
        API_HOST = f'http://{API_HOST}'

    if authorization_key and len(authorization_key) > 0:
        response = requests.post(f'{API_HOST}/api/json/?authorization_key={authorization_key}', headers=headers, data=data, files=files)
    else:    
        response = requests.post(f'{API_HOST}/api/json/', headers=headers, data=data)

    json_response = json.dumps(response.json())

【讨论】:

  • 嗨!这给了我ValueError: I/O operation on closed file.
猜你喜欢
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 2013-10-30
相关资源
最近更新 更多