【问题标题】:Generating file to download with Django使用 Django 生成要下载的文件
【发布时间】:2010-10-28 20:08:44
【问题描述】:

是否可以制作一个 zip 存档并提供下载,但仍不能将文件保存到硬盘驱动器?

【问题讨论】:

标签: python django


【解决方案1】:

要触发下载,您需要设置Content-Disposition 标头:

from django.http import HttpResponse
from wsgiref.util import FileWrapper

# generate the file
response = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response

如果你不想要磁盘上的文件,你需要使用StringIO

import cStringIO as StringIO

myfile = StringIO.StringIO()
while not_finished:
    # generate chunk
    myfile.write(chunk)

您也可以选择设置Content-Length 标头:

response['Content-Length'] = myfile.tell()

【讨论】:

  • 我认为 Django 中间件可能会自动发生 Content-Length
  • 使用这个例子下载一个总是空的文件,有什么想法吗?
  • 正如@eleaz28 所说,在我的情况下它也在创建空白文件。我刚刚删除了FileWrapper,它起作用了。
  • 此答案不适用于 Django 1.9:请参阅:stackoverflow.com/a/35485073/375966
  • 我以读取模式打开文件然后 file.getvalue() 给出属性错误:TextIOWrapper has no attribute getValue .
【解决方案2】:

您会更乐意创建一个临时文件。这样可以节省大量内存。当您同时拥有一两个以上的用户时,您会发现节省内存非常非常重要。

但是,您可以写入 StringIO 对象。

>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())
778

“缓冲区”对象类似于文件,具有 778 字节的 ZIP 存档。

【讨论】:

  • 关于节省内存的好点。但是如果使用临时文件,你会把删除它的代码放在哪里?
  • @superjoe30:定期清理工作。 Django 已经有一个管理命令,必须定期运行才能删除旧会话。
  • @superjoe30 这就是 /tmp 的用途 :)
  • @S.Lott 是否可以使用 mod x-sendfile 提供创建的文件(在您的示例中为 z in)?
【解决方案3】:

为什么不制作一个 tar 文件呢?像这样:

def downloadLogs(req, dir):
    response = HttpResponse(content_type='application/x-gzip')
    response['Content-Disposition'] = 'attachment; filename=download.tar.gz'
    tarred = tarfile.open(fileobj=response, mode='w:gz')
    tarred.add(dir)
    tarred.close()

    return response

【讨论】:

  • 对于较新版本的 Django,您应该使用 content_type= 而不是 mimetype=
【解决方案4】:

是的,您可以使用zipfile modulezlib module 或其他compression modules 在内存中创建一个 zip 存档。您可以让您的视图将 zip 存档写入 Django 视图返回的 HttpResponse 对象,而不是将上下文发送到模板。最后,您需要将 mimetype 设置为 tell the browser to treat the response as a file 的适当格式。

【讨论】:

    【解决方案5】:

    models.py

    from django.db import models
    
    class PageHeader(models.Model):
        image = models.ImageField(upload_to='uploads')
    

    views.py

    from django.http import HttpResponse
    from StringIO import StringIO
    from models import *
    import os, mimetypes, urllib
    
    def random_header_image(request):
        header = PageHeader.objects.order_by('?')[0]
        image = StringIO(file(header.image.path, "rb").read())
        mimetype = mimetypes.guess_type(os.path.basename(header.image.name))[0]
    
        return HttpResponse(image.read(), mimetype=mimetype)
    

    【讨论】:

    • 在内存中创建图像大小的字符串看起来不安全。
    【解决方案6】:
    def download_zip(request,file_name):
        filePath = '<path>/'+file_name
        fsock = open(file_name_with_path,"rb")
        response = HttpResponse(fsock, content_type='application/zip')
        response['Content-Disposition'] = 'attachment; filename=myfile.zip'
        return response
    

    您可以根据需要替换 zip 和内容类型。

    【讨论】:

    • 你的意思是fsock = open(filePath,"rb")
    【解决方案7】:

    与内存中的 tgz 存档相同:

    import tarfile
    from io import BytesIO
    
    
    def serve_file(request):
        out = BytesIO()
        tar = tarfile.open(mode = "w:gz", fileobj = out)
        data = 'lala'.encode('utf-8')
        file = BytesIO(data)
        info = tarfile.TarInfo(name="1.txt")
        info.size = len(data)
        tar.addfile(tarinfo=info, fileobj=file)
        tar.close()
    
        response = HttpResponse(out.getvalue(), content_type='application/tgz')
        response['Content-Disposition'] = 'attachment; filename=myfile.tgz'
        return response
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-05
      • 1970-01-01
      • 1970-01-01
      • 2022-07-14
      • 2023-03-21
      • 2014-08-08
      • 2019-09-12
      • 2017-06-02
      相关资源
      最近更新 更多