Improve DownloadView for cStringIO file download response

This commit is contained in:
Rémy HUBSCHER 2013-02-05 10:51:11 +01:00
parent a012b11e97
commit f9fe4f3a2f
2 changed files with 37 additions and 12 deletions

View file

@ -14,7 +14,7 @@ class DownloadResponse(HttpResponse):
"""
def __init__(self, file_instance, attachment=True, basename=None,
status=200, content_type=None):
status=200, content_type=None, size=None):
"""Constructor.
It differs a bit from HttpResponse constructor.
@ -42,6 +42,9 @@ class DownloadResponse(HttpResponse):
response (default implementation uses mimetypes, based on file name).
Defaults is ``None``.
size:
Size of the file response
"""
self.file = file_instance
super(DownloadResponse, self).__init__(content=self.file,
@ -49,6 +52,8 @@ class DownloadResponse(HttpResponse):
content_type=content_type)
self.basename = basename
self.attachment = attachment
self.content_type = content_type
self.size = size
if not content_type:
del self['Content-Type'] # Will be set later.
# Apply default headers.
@ -69,7 +74,7 @@ class DownloadResponse(HttpResponse):
except AttributeError:
headers = {}
headers['Content-Type'] = self.get_content_type()
headers['Content-Length'] = self.file.size
headers['Content-Length'] = self.get_size()
if self.attachment:
headers['Content-Disposition'] = 'attachment; filename=%s' \
% self.get_basename()
@ -95,12 +100,15 @@ class DownloadResponse(HttpResponse):
def get_content_type(self):
"""Return a suitable "Content-Type" header for ``self.file``."""
try:
return self.file.content_type
except AttributeError:
content_type_template = '%(mime_type)s; charset=%(charset)s'
return content_type_template % {'mime_type': self.get_mime_type(),
'charset': self.get_charset()}
if not self.content_type:
try:
return self.file.content_type
except AttributeError:
content_type_template = '%(mime_type)s; charset=%(charset)s'
return content_type_template % {
'mime_type': self.get_mime_type(),
'charset': self.get_charset()}
return self.content_type
def get_mime_type(self):
"""Return mime-type of the file."""
@ -119,6 +127,12 @@ class DownloadResponse(HttpResponse):
"""Return the charset of the file to serve."""
return settings.DEFAULT_CHARSET
def get_size(self):
"""Return the size of the file to serve."""
if not self.size:
self.size = self.file.size
return self.size
def is_download_response(response):
"""Return ``True`` if ``response`` is a download response.

View file

@ -40,6 +40,15 @@ class DownloadMixin(object):
def get_basename(self):
return self.basename
def get_size(self):
return self.get_file().size
def get_modification_time(self):
return self.get_file().modified_time
def get_content_type(self):
return self.get_file().content_type
def render_to_response(self, *args, **kwargs):
"""Returns a response with a file as attachment."""
# Respect the If-Modified-Since header.
@ -47,16 +56,18 @@ class DownloadMixin(object):
if_modified_since = self.request.META.get('HTTP_IF_MODIFIED_SINCE',
None)
if if_modified_since is not None:
modification_time = file_instance.modified_time
size = file_instance.size
modification_time = self.get_modification_time()
size = self.get_size()
if not was_modified_since(if_modified_since, modification_time,
size):
content_type = file_instance.content_type
content_type = self.get_content_type()
return HttpResponseNotModified(content_type=content_type)
# Return download response.
response_kwargs = {'file_instance': file_instance,
'attachment': self.attachment,
'basename': self.get_basename()}
'basename': self.get_basename(),
'size': self.get_size(),
'content_type': self.get_content_type()}
response_kwargs.update(kwargs)
response = self.response_class(**response_kwargs)
return response