Ошибка памяти Django Filewrapper при обслуживании больших файлов
У меня есть такой код:
@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
Кажется, это работает. Однако, если я загружаю больший файл (например, ~600 МБ), мое потребление памяти увеличивается на эти 600 МБ. После нескольких таких загрузок мой сервер выдает:
Внутренняя ошибка сервера: /download/ Traceback (последний вызов был последним):
Файл "/home/matous/.local/lib/python3.5/site-packages/django/core/handlers/exception.py", строка 35, во внутреннем ответе = файл get_response(запрос) "/home/matous/.local/lib/python3.5/site-packages/django/core/handlers/base.py", строка 128, в _get_response response = self.process_exception_by_middleware(e, запрос) Файл" /home/matous/.local/lib/ python3.5 / site-packages / django / core / handlers / base.py ", строка 126, в _get_response response = wrapped_callback(запрос, *callback_args, **callback_kwargs) файл"/home/matous/.local/lib/python3.5/site-packages/django/contrib/auth/decorators.py", строка 21, в _wrapped_view возвращать view_func(запрос, *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, в init self.content = файл содержимого" /home/matous/.local/lib/ python3.5 / site-packages / django / http / response.py ", строка 308, в содержимом content = b''.join(self.make_bytes(chunk) для фрагмента в значении) MemoryError
Что я делаю не так? Можно ли как-то настроить его для потоковой передачи по частям с жесткого диска без этой безумной памяти?
Примечание: я знаю, что большие файлы не должны обслуживаться Django, но я ищу простой подход, который позволяет проверять права доступа пользователя для любого обслуживаемого файла.
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
оптимизирован для бинарных файлов.