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

mat*_*usc 1 python django streaming file download

我有这样的代码:

@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
Run Code Online (Sandbox Code Playgroud)

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

内部服务器错误:/download/ 回溯(最近一次调用最后一次):
文件“/home/matous/.local/lib/python3.5/site-packages/django/core/handlers/exception.py”,第 35 行,在内部响应 = get_response(request) 文件“/home/matous/. local/lib/python3.5/site-packages/django/core/handlers/base.py", line 128, in _get_response response = self.process_exception_by_middleware(e, request) File "/home/matous/.local/lib/ python3.5/site-packages/django/core/handlers/base.py”,第 126 行,在 _get_response 响应 =wrapped_callback(request, *callback_args, **callback_kwargs) 文件“/home/matous/.local/lib/python3 .5/site-packages/django/contrib/auth/decorators.py”,第 21 行,在 _wrapped_view 中返回 view_func(request, *args, **kwargs) 文件“/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) 文件“/home/matous/.local/lib/python3.5/site-packages/django/http/response.py”,第 285 行,在在里面 self.content = content File "/home/matous/.local/lib/python3.5/site-packages/django/http/response.py", line 308, in content content = b''.join(self. make_bytes(chunk) for chunk in value) MemoryError

我做错了什么?是否有可能以某种方式对其进行配置,以便在没有这种疯狂的内存存储的情况下从硬盘驱动器逐个流式传输它?

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

tri*_*het 7

尝试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(file_path)
   chunk_size = 8192
   response = StreamingHttpResponse(
       FileWrapper(open(file_path, 'rb'), chunk_size),
       content_type="application/octet-stream"
   )
   response['Content-Length'] = os.path.getsize(file_path)    
   response['Content-Disposition'] = "attachment; filename=%s" % filename
   return response
Run Code Online (Sandbox Code Playgroud)

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

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