4

我有以下视图代码,它尝试将 zip 文件“流式传输”到客户端以供下载:

import os
import zipfile
import tempfile
from pyramid.response import FileIter

def zipper(request):
    _temp_path = request.registry.settings['_temp']
    tmpfile = tempfile.NamedTemporaryFile('w', dir=_temp_path, delete=True)

    tmpfile_path = tmpfile.name

    ## creating zipfile and adding files
    z = zipfile.ZipFile(tmpfile_path, "w")
    z.write('somefile1.txt')
    z.write('somefile2.txt')
    z.close()

    ## renaming the zipfile
    new_zip_path = _temp_path + '/somefilegroup.zip'
    os.rename(tmpfile_path, new_zip_path)

    ## re-opening the zipfile with new name
    z = zipfile.ZipFile(new_zip_path, 'r')
    response = FileIter(z.fp)

    return response

但是,这是我在浏览器中得到的响应:

Could not convert return value of the view callable function newsite.static.zipper into a response object. The value returned was .

我想我没有正确使用 FileIter。


更新:

自从根据 Michael Merickel 的建议进行更新后,FileIter 函数工作正常。然而,仍然挥之不去的是客户端(浏览器)上出现的 MIME 类型错误: Resource interpreted as Document but transferred with MIME type application/zip: "http://newsite.local:6543/zipper?data=%7B%22ids%22%3A%5B6%2C7%5D%7D"

为了更好地说明这个问题,我在 Github 上包含了一个小文件:.pyhttps ://github.com/thapar/zipper-fix.pt

4

2 回答 2

9

FileIter不是响应对象,就像您的错误消息说的那样。它是一个可用于响应主体的可迭代对象,就是这样。也ZipFile可以接受文件对象,这比文件路径更有用。让我们尝试写入tmpfile,然后将该文件指针倒回到开头,并使用它写出而不进行任何花哨的重命名。

import os
import zipfile
import tempfile
from pyramid.response import FileIter

def zipper(request):
    _temp_path = request.registry.settings['_temp']
    fp = tempfile.NamedTemporaryFile('w+b', dir=_temp_path, delete=True)

    ## creating zipfile and adding files
    z = zipfile.ZipFile(fp, "w")
    z.write('somefile1.txt')
    z.write('somefile2.txt')
    z.close()

    # rewind fp back to start of the file
    fp.seek(0)

    response = request.response
    response.content_type = 'application/zip'
    response.app_iter = FileIter(fp)
    return response

我根据文档将模式更改NamedTemporaryFile'w+b'允许写入读取文件。

于 2013-04-05T15:12:04.663 回答
0

当前 Pyramid 版本为此用例提供了 2 个便利类 - FileResponse、FileIter。下面的代码片段将提供一个静态文件。我运行了这段代码——下载的文件被命名为“下载”,就像视图名称一样。要更改文件名等,请设置 Content-Disposition 标头或查看 pyramid.response.Response 的参数。

from pyramid.response import FileResponse

@view_config(name="download")
def zipper(request):    
    path = 'path_to_file'
    return FileResponse(path, request) #passing request is required

文档: http ://docs.pylonsproject.org/projects/pyramid/en/latest/api/response.html#

提示:如果可能,从视图中提取 Zip 逻辑

于 2013-04-05T07:40:48.187 回答