From f9fe4f3a2fb66eb72ead3dfcad3a8d212eb871e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 5 Feb 2013 10:51:11 +0100 Subject: [PATCH] Improve DownloadView for cStringIO file download response --- django_downloadview/response.py | 30 ++++++++++++++++++++++-------- django_downloadview/views.py | 19 +++++++++++++++---- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/django_downloadview/response.py b/django_downloadview/response.py index 41e8353..3a6f45f 100644 --- a/django_downloadview/response.py +++ b/django_downloadview/response.py @@ -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. diff --git a/django_downloadview/views.py b/django_downloadview/views.py index 9792d82..101bb33 100644 --- a/django_downloadview/views.py +++ b/django_downloadview/views.py @@ -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