mirror of
https://github.com/jazzband/django-downloadview.git
synced 2026-03-16 22:40:25 +00:00
Refs #3 - Introduced DownloadResponse.
This commit is contained in:
parent
0ae3653d1e
commit
5a432dc700
2 changed files with 67 additions and 10 deletions
52
django_downloadview/response.py
Normal file
52
django_downloadview/response.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"""HttpResponse subclasses."""
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
class DownloadResponse(HttpResponse):
|
||||
"""File download response."""
|
||||
def __init__(self, content, content_type, content_length, basename,
|
||||
status=200, content_encoding=None, expires=None,
|
||||
filename=None):
|
||||
"""Constructor.
|
||||
|
||||
It differs a bit from HttpResponse constructor.
|
||||
|
||||
Required arguments:
|
||||
|
||||
* ``content`` is supposed to be an iterable that can read the file.
|
||||
Consider :py:class:`wsgiref.util.FileWrapper`` as a good candidate.
|
||||
|
||||
* ``content_type`` contains mime-type and charset of the file.
|
||||
It is used as "Content-Type" header.
|
||||
|
||||
* ``content_length`` is the size, in bytes, of the file.
|
||||
It is used as "Content-Length" header.
|
||||
|
||||
* ``basename`` is the client-side name of the file ("save as" name).
|
||||
It is used in "Content-Disposition" header.
|
||||
|
||||
Optional arguments:
|
||||
|
||||
* ``status`` is HTTP status code.
|
||||
|
||||
* ``content_encoding`` is used for "Content-Encoding" header.
|
||||
|
||||
* ``expires`` is a datetime.
|
||||
It is used to set the "Expires" header.
|
||||
|
||||
* ``filename`` is the server-side name of the file.
|
||||
It may be used by decorators or middlewares to delegate the actual
|
||||
streaming to a more efficient server (i.e. Nginx, Lighttpd...).
|
||||
|
||||
"""
|
||||
super(DownloadResponse, self).__init__(content=content, status=status,
|
||||
content_type=content_type)
|
||||
self.filename = filename
|
||||
self.basename = basename
|
||||
self['Content-Length'] = content_length
|
||||
if content_encoding:
|
||||
self['Content-Encoding'] = content_encoding
|
||||
self.expires = expires
|
||||
if expires:
|
||||
self['Expires'] = expires
|
||||
self['Content-Disposition'] = 'attachment; filename=%s' % basename
|
||||
|
|
@ -6,11 +6,13 @@ from wsgiref.util import FileWrapper
|
|||
from django.conf import settings
|
||||
from django.core.files import File
|
||||
from django.core.files.storage import DefaultStorage
|
||||
from django.http import Http404, HttpResponse, HttpResponseNotModified
|
||||
from django.http import Http404, HttpResponseNotModified
|
||||
from django.views.generic.base import View
|
||||
from django.views.generic.detail import BaseDetailView
|
||||
from django.views.static import was_modified_since
|
||||
|
||||
from django_downloadview.response import DownloadResponse
|
||||
|
||||
|
||||
class DownloadMixin(object):
|
||||
"""Placeholders and base implementation to create file download views.
|
||||
|
|
@ -27,7 +29,7 @@ class DownloadMixin(object):
|
|||
|
||||
"""
|
||||
#: Response class to be used in render_to_response().
|
||||
response_class = HttpResponse
|
||||
response_class = DownloadResponse
|
||||
|
||||
def get_file(self):
|
||||
"""Return a django.core.files.File object, which is to be served."""
|
||||
|
|
@ -130,13 +132,16 @@ class DownloadMixin(object):
|
|||
basename = self.get_basename()
|
||||
encoding = self.get_encoding()
|
||||
wrapper = self.get_file_wrapper()
|
||||
response = self.response_class(wrapper, content_type=content_type)
|
||||
if encoding:
|
||||
response['Content-Encoding'] = encoding
|
||||
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' % basename
|
||||
response = self.response_class(content=wrapper,
|
||||
content_type=content_type,
|
||||
content_length=size,
|
||||
filename=filename,
|
||||
basename=basename,
|
||||
content_encoding=encoding,
|
||||
expires=None)
|
||||
# Do not close the file as response class may need it open: the wrapper
|
||||
# is an iterator on the content of the file.
|
||||
# Garbage collector will close the file.
|
||||
return response
|
||||
|
||||
|
||||
|
|
@ -172,7 +177,7 @@ class DownloadView(DownloadMixin, View):
|
|||
self._file = File(open(self.filename))
|
||||
return self._file
|
||||
except IOError:
|
||||
raise Http404
|
||||
raise Http404()
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""Handle GET requests: stream a file."""
|
||||
|
|
|
|||
Loading…
Reference in a new issue