mirror of
https://github.com/jazzband/django-downloadview.git
synced 2026-03-16 22:40:25 +00:00
Refs #13 - Using Django's StreamingHttpResponse. Requires Django>=1.5. Introduced django_downloadview.test.assert_download_response().
This commit is contained in:
parent
5159adae93
commit
5a3ff57e23
7 changed files with 87 additions and 10 deletions
|
|
@ -6,8 +6,14 @@ Changelog
|
|||
|
||||
**Backward incompatible changes.**
|
||||
|
||||
- Using StreamingHttpResponse introduced with Django 1.5. Makes Django 1.5 a
|
||||
requirement!
|
||||
|
||||
- Added ``django_downloadview.test.assert_download_response`` utility.
|
||||
|
||||
- Download views and response now use file wrappers. Most logic around file
|
||||
attributes, formerly in views, moved to wrappers.
|
||||
|
||||
- Replaced DownloadView by PathDownloadView and StorageDownloadView. Use the
|
||||
right one depending on the use case.
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class DownloadTestCase(TestCase):
|
|||
self.assertEquals(response['Content-Disposition'],
|
||||
'attachment; filename=hello-world.txt')
|
||||
self.assertEqual(open(self.files['hello-world.txt']).read(),
|
||||
response.content)
|
||||
''.join(response.streaming_content))
|
||||
|
||||
|
||||
class PathDownloadViewTestCase(DownloadTestCase):
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ DATABASES = {
|
|||
}
|
||||
|
||||
|
||||
# Required.
|
||||
SECRET_KEY = "This is a secret made public on project's repository."
|
||||
|
||||
# Media and static files.
|
||||
MEDIA_ROOT = join(data_dir, 'media')
|
||||
MEDIA_URL = '/media/'
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import os
|
|||
import mimetypes
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse
|
||||
from django.http import StreamingHttpResponse
|
||||
|
||||
|
||||
class DownloadResponse(HttpResponse):
|
||||
class DownloadResponse(StreamingHttpResponse):
|
||||
"""File download response.
|
||||
|
||||
``content`` attribute is supposed to be a file object wrapper, which makes
|
||||
|
|
@ -44,7 +44,7 @@ class DownloadResponse(HttpResponse):
|
|||
|
||||
"""
|
||||
self.file = file_instance
|
||||
super(DownloadResponse, self).__init__(content=self.file,
|
||||
super(DownloadResponse, self).__init__(streaming_content=self.file,
|
||||
status=status,
|
||||
content_type=content_type)
|
||||
self.basename = basename
|
||||
|
|
@ -88,7 +88,7 @@ class DownloadResponse(HttpResponse):
|
|||
|
||||
def get_basename(self):
|
||||
"""Return basename."""
|
||||
if self.attachment and self.basename:
|
||||
if self.basename:
|
||||
return self.basename
|
||||
else:
|
||||
return os.path.basename(self.file.name)
|
||||
|
|
@ -98,9 +98,9 @@ class DownloadResponse(HttpResponse):
|
|||
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()}
|
||||
content_type_template = '{mime_type}; charset={charset}'
|
||||
return content_type_template.format(mime_type=self.get_mime_type(),
|
||||
charset=self.get_charset())
|
||||
|
||||
def get_mime_type(self):
|
||||
"""Return mime-type of the file."""
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import tempfile
|
|||
from django.conf import settings
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from django_downloadview.response import is_download_response
|
||||
|
||||
|
||||
class temporary_media_root(override_settings):
|
||||
"""Context manager or decorator to override settings.MEDIA_ROOT.
|
||||
|
|
@ -40,3 +42,69 @@ class temporary_media_root(override_settings):
|
|||
setting."""
|
||||
shutil.rmtree(settings.MEDIA_ROOT)
|
||||
super(temporary_media_root, self).disable()
|
||||
|
||||
|
||||
class DownloadResponseValidator(object):
|
||||
"""Utility class to validate DownloadResponse instances."""
|
||||
def __call__(self, test_case, response, **assertions):
|
||||
"""Assert that ``response`` is a valid DownloadResponse instance.
|
||||
|
||||
Optional ``assertions`` dictionary can be used to check additional
|
||||
items:
|
||||
|
||||
* ``basename``: the basename of the file in the response.
|
||||
|
||||
* ``content_type``: the value of "Content-Type" header.
|
||||
|
||||
* ``mime_type``: the MIME type part of "Content-Type" header (without
|
||||
charset).
|
||||
|
||||
* ``content``: the contents of the file.
|
||||
|
||||
* ``attachment``: whether the file is returned as attachment or not.
|
||||
|
||||
"""
|
||||
self.assert_download_response(test_case, response)
|
||||
for key, value in assertions.iteritems():
|
||||
assert_func = getattr(self, 'assert_%s' % key)
|
||||
assert_func(test_case, response, value)
|
||||
|
||||
def assert_download_response(self, test_case, response):
|
||||
test_case.assertTrue(is_download_response(response))
|
||||
|
||||
def assert_basename(self, test_case, response, value):
|
||||
test_case.assertEqual(response.basename, value)
|
||||
test_case.assertTrue('filename={name}'.format(name=response.basename),
|
||||
value)
|
||||
|
||||
def assert_content_type(self, test_case, response, value):
|
||||
test_case.assertEqual(response['Content-Type'], value)
|
||||
|
||||
def assert_mime_type(self, test_case, response, value):
|
||||
test_case.assertTrue(response['Content-Type'].startswith(value))
|
||||
|
||||
def assert_content(self, test_case, response, value):
|
||||
test_case.assertEqual(response.file.read(), value)
|
||||
test_case.assertEqual(''.join(response.streaming_content), value)
|
||||
|
||||
def assert_attachment(self, test_case, response, value):
|
||||
test_case.assertEqual('attachment;' in response['Content-Disposition'],
|
||||
value)
|
||||
|
||||
|
||||
def assert_download_response(test_case, response, **assertions):
|
||||
"""Make ``test_case`` assert that ``response`` is a DownloadResponse.
|
||||
|
||||
Optional ``assertions`` dictionary can be used to check additional items:
|
||||
|
||||
* ``basename``: the basename of the file in the response.
|
||||
|
||||
* ``content_type``: the value of "Content-Type" header.
|
||||
|
||||
* ``charset``: the value of ``X-Accel-Charset`` header.
|
||||
|
||||
* ``content``: the content of the file to be downloaded.
|
||||
|
||||
"""
|
||||
validator = DownloadResponseValidator()
|
||||
return validator(test_case, response, **assertions)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ recipe = z3c.recipe.scripts
|
|||
eggs = zest.releaser
|
||||
|
||||
[versions]
|
||||
Django = 1.4.3
|
||||
Django = 1.5
|
||||
Jinja2 = 2.6
|
||||
Pygments = 1.6
|
||||
Sphinx = 1.1.3
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -15,7 +15,7 @@ NAME = 'django-downloadview'
|
|||
README = read_relative_file('README')
|
||||
VERSION = read_relative_file('VERSION')
|
||||
PACKAGES = ['django_downloadview']
|
||||
REQUIRES = ['setuptools', 'django>=1.4']
|
||||
REQUIRES = ['setuptools', 'django>=1.5']
|
||||
|
||||
|
||||
if __name__ == '__main__': # Don't run setup() when we import this module.
|
||||
|
|
|
|||
Loading…
Reference in a new issue