Django Filewrapper内存错误服务大文件,如何流

时间:2018-02-23 13:31:30

标签: python django file download streaming

我有这样的代码:

@login_required
def download_file(request):
    content_type = "application/octet-stream"
    download_name = os.path.join(DATA_ROOT, "video.avi")

    with open(download_name, "rb") as f:
        wrapper = FileWrapper(f, 8192)
        response = HttpResponse(wrapper, content_type=content_type)
    response['Content-Disposition'] = 'attachment; filename=blabla.avi'
    response['Content-Length'] = os.path.getsize(download_name)
    # response['Content-Length'] = _file.size
    return response

似乎它有效。但是,如果我下载更大的文件(例如~600MB),我的内存消耗会增加600MB。经过几次这样的下载,我的服务器抛出:

  

内部服务器错误:/ download / Traceback(最近一次调用最后一次):
  文件   " /home/matous/.local/lib/python3.5/site-packages/django/core/handlers/exception.py" ;,   第35行,在内部       response = get_response(request)File" /home/matous/.local/lib/python3.5/site-packages/django/core/handlers/base.py",   第128行,在_get_response中       response = self.process_exception_by_middleware(e,request)File" /home/matous/.local/lib/python3.5/site-packages/django/core/handlers/base.py",   第76行,在_get_response中       response = wrapped_callback(request,* callback_args,** callback_kwargs)File" /home/matous/.local/lib/python3.5/site-packages/django/contrib/auth/decorators.py",   第21行,在_wrapped_view中       return view_func(request,* args,** kwargs)File" /media/matous/89104d3d-fa52-4b14-9c5d-9ec54ceebebb/home/matous/phd/emoapp/emoapp/mainapp/views.py" ,   第118行,在download_file中       response = HttpResponse(wrapper,content_type = content_type)File" /home/matous/.local/lib/python3.5/site-packages/django/http/response.py",   第285行,在 init 中       self.content = content File" /home/matous/.local/lib/python3.5/site-packages/django/http/response.py",   第308行,内容       content = b' .join(self.make_bytes(chunk)for chunk in value)MemoryError

我做错了什么?是否有可能以某种方式将其配置为从硬盘驱动器逐个流式传输而没有这种疯狂的内存存储?

注意:我知道Django不应该提供大文件,但我正在寻找简单的方法,允许验证任何服务文件的用户访问权限。

1 个答案:

答案 0 :(得分:1)

尝试使用StreamingHttpResponse代替,这将有所帮助,它正是您所寻找的。

是否有可能以某种方式将其配置为从硬盘驱动器逐个流式传输而没有这种疯狂的内存存储?

import os
from django.http import StreamingHttpResponse
from django.core.servers.basehttp import FileWrapper #django <=1.8
from wsgiref.util import FileWrapper #django >1.8

@login_required
def download_file(request):
   file_path = os.path.join(DATA_ROOT, "video.avi")
   filename = os.path.basename(the_file)
   chunk_size = 8192
   response = StreamingHttpResponse(
       FileWrapper(open(file_path, 'rb'), chunk_size),
       content_type="application/octet-stream"
   )
   response['Content-Length'] = os.path.getsize(the_file)    
   response['Content-Disposition'] = "attachment; filename=%s" % filename
   return response

这将以块的形式传输文件而不将其加载到内存中;或者,您可以使用FileResponse

  

是针对二进制优化的StreamingHttpResponse的子类   文件。