From 5a2a174b3ed171c57239f20d19a7c2ad58ef062e Mon Sep 17 00:00:00 2001 From: Benoit Bryon Date: Tue, 28 Aug 2012 10:46:02 +0200 Subject: [PATCH] Reduced memory usage when serving files: return an iterator of chunks, don't load the whole file into memory. --- django_downloadview/views.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/django_downloadview/views.py b/django_downloadview/views.py index ec7f406..e83d4e9 100644 --- a/django_downloadview/views.py +++ b/django_downloadview/views.py @@ -1,5 +1,6 @@ -from os.path import abspath, basename +import os import shutil +from wsgiref.util import FileWrapper from django.core.files import File from django.http import HttpResponse @@ -20,16 +21,19 @@ class DownloadMixin(object): mime_type = self.get_mime_type() if isinstance(self.file, File): absolute_filename = self.file.path + wrapper = FileWrapper(self.file.file) + size = self.file.size else: - absolute_filename = abspath(self.file) - filename = basename(absolute_filename) - response = self.response_class(mimetype=mime_type) - # Open file as read binary. - with open(absolute_filename, 'rb') as f: - shutil.copyfileobj(f, response) + absolute_filename = os.path.abspath(self.file) + wrapper = FileWrapper(file(absolute_filename)) + size = os.path.getsize(absolute_filename) + basename = os.path.basename(absolute_filename) + response = self.response_class(wrapper, content_type=mime_type, + mimetype=mime_type) + response['Content-Length'] = size # Do not call fsock.close() as HttpResponse needs it open # Garbage collector will close it - response['Content-Disposition'] = 'attachment; filename=%s' % filename + response['Content-Disposition'] = 'attachment; filename=%s' % basename return response