Django,关于zip文件响应的问题

3 投票
1 回答
9010 浏览
提问于 2025-04-16 08:54

我在用Django发送请求时遇到了一个问题。我的应用程序会把一些数据写入文件,然后把这些文件打包成一个压缩文件(zip)。但是,当我返回一个附件响应时,浏览器虽然会下载这个文件,但下载下来的zip文件是坏的(损坏的)。原本的zip文件里是我的文件,没有任何错误。

我的代码在这里:

        file_path = "/root/Programs/media/statics/schedules/"
        zip_file_name = file_path + "test.zip"
        zip_file = zipfile.ZipFile(zip_file_name, "w")
        for i in range(len(planner_list)):
                file_name = file_path + str(planner_list[i][0].start_date)
                render_to_file('deneme.html',file_name ,{'schedule':schedule})
                zip_file.write(file_name, os.path.basename(file_name),zipfile.ZIP_DEFLATED)
                os.remove(file_name)
        zip_file.close()

        response = HttpResponse(file_path , content_type='application/zip')
        response['Content-Disposition'] = 'attachment; filename=test.zip'
        return response

1 个回答

13

HttpResponse可以接受一个字符串或者一个返回字符串的迭代器(就像一个打开的文件对象)。你现在传入的是文件路径,所以响应的内容只是这个文件路径,而不是你写入文件的有效zip内容。你可以直接使用open,因为HTTPResponse对象会帮你关闭文件:

response = HttpResponse(open(file_path, 'rb'), content_type='application/zip')

引用文档中的内容:

最后,你可以给HttpResponse传递一个迭代器,而不是字符串。HttpResponse会立即处理这个迭代器,把它的内容存储为字符串,然后丢弃它。像文件和生成器这样的对象,如果有close()方法,会立即被关闭。

如果你需要将响应从迭代器流式传输到客户端,你必须使用StreamingHttpResponse类。

每次请求都写入磁盘可能会影响你服务器的输入输出性能——从你的代码来看,所有内容似乎都足够小,可以放在内存中。你可以使用(C)StringIO(在Python3中是BytesIO)来代替真实的文件:

from io import BytesIO

mem_file = BytesIO()
with zipfile.ZipFile(mem_file, "w") as zip_file:
    for i, planner in enumerate(planner_list):
        file_name = str(planner[0].start_date)
        content = render_to_string('deneme.html', {'schedule':schedule})
    zip_file.writestr(file_name, content)

f.seek(0)  # rewind file pointer just in case
response = HttpResponse(f, content_type='application/zip')

撰写回答