From a45c79552e799ba70ccc2c3654548176538fc08e Mon Sep 17 00:00:00 2001 From: Benoit Bryon Date: Mon, 27 Aug 2012 17:05:24 +0200 Subject: [PATCH] Introduced ObjectDownloadView. UNSTABLE. Work in progress. --- demo/demoproject/download/models.py | 8 +++++++ demo/demoproject/download/tests.py | 33 +++++++++++++++++++++++++---- demo/demoproject/download/urls.py | 4 +++- demo/demoproject/download/views.py | 7 +++++- django_downloadview/__init__.py | 2 +- django_downloadview/views.py | 28 ++++++++++++++++++------ 6 files changed, 68 insertions(+), 14 deletions(-) diff --git a/demo/demoproject/download/models.py b/demo/demoproject/download/models.py index e69de29..4c89ae5 100644 --- a/demo/demoproject/download/models.py +++ b/demo/demoproject/download/models.py @@ -0,0 +1,8 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ + + +class Document(models.Model): + """A sample model with a FileField.""" + slug = models.SlugField(verbose_name=_('slug')) + file = models.FileField(verbose_name=_('file'), upload_to='document') diff --git a/demo/demoproject/download/tests.py b/demo/demoproject/download/tests.py index a5a3ccc..da0734b 100644 --- a/demo/demoproject/download/tests.py +++ b/demo/demoproject/download/tests.py @@ -2,24 +2,32 @@ from os import listdir from os.path import abspath, dirname, join -from django.core.urlresolvers import reverse +from django.core.files import File +from django.core.urlresolvers import reverse_lazy as reverse from django.test import TestCase +from demoproject.download.models import Document + app_dir = dirname(abspath(__file__)) fixtures_dir = join(app_dir, 'fixtures') -class DownloadViewTestCase(TestCase): - """Test generic DownloadView.""" +class DownloadTestCase(TestCase): + """Base class for download tests.""" def setUp(self): """Common setup.""" - super(DownloadViewTestCase, self).setUp() + super(DownloadTestCase, self).setUp() self.download_hello_world_url = reverse('download_hello_world') + self.download_document_url = reverse('download_document', + kwargs={'slug': 'hello-world'}) self.files = {} for f in listdir(fixtures_dir): self.files[f] = abspath(join(fixtures_dir, f)) + +class DownloadViewTestCase(DownloadTestCase): + """Test generic DownloadView.""" def test_download_hello_world(self): """Download_hello_world view returns hello-world.txt as attachement.""" response = self.client.get(self.download_hello_world_url) @@ -29,3 +37,20 @@ class DownloadViewTestCase(TestCase): 'attachment; filename=hello-world.txt') self.assertEqual(open(self.files['hello-world.txt']).read(), response.content) + + +class ObjectDownloadViewTestCase(DownloadTestCase): + """Test generic ObjectDownloadView.""" + def test_download_hello_world(self): + """Download_hello_world view returns hello-world.txt as attachement.""" + document = Document.objects.create( + slug='hello-world', + file=File(open(self.files['hello-world.txt'])), + ) + response = self.client.get(self.download_document_url) + self.assertEquals(response.status_code, 200) + self.assertEquals(response['Content-Type'], 'application/octet-stream') + self.assertEquals(response['Content-Disposition'], + 'attachment; filename=hello-world.txt') + self.assertEqual(open(self.files['hello-world.txt']).read(), + response.content) diff --git a/demo/demoproject/download/urls.py b/demo/demoproject/download/urls.py index 0a80f62..477aa40 100644 --- a/demo/demoproject/download/urls.py +++ b/demo/demoproject/download/urls.py @@ -3,6 +3,8 @@ from django.conf.urls import patterns, include, url urlpatterns = patterns('demoproject.download.views', - url(r'^download/hello-world\.txt$', 'download_hello_world', + url(r'^hello-world\.txt$', 'download_hello_world', name='download_hello_world'), + url(r'^document/(?P[a-zA-Z0-9_-]+)/$', 'download_document', + name='download_document'), ) diff --git a/demo/demoproject/download/views.py b/demo/demoproject/download/views.py index bf62e98..55151f0 100644 --- a/demo/demoproject/download/views.py +++ b/demo/demoproject/download/views.py @@ -1,6 +1,8 @@ from os.path import abspath, dirname, join -from django_downloadview import DownloadView +from django_downloadview import DownloadView, ObjectDownloadView + +from demoproject.download.models import Document app_dir = dirname(abspath(__file__)) @@ -9,3 +11,6 @@ hello_world_file = join(fixtures_dir, 'hello-world.txt') download_hello_world = DownloadView.as_view(file=hello_world_file) + + +download_document = ObjectDownloadView.as_view(model=Document) diff --git a/django_downloadview/__init__.py b/django_downloadview/__init__.py index 2472765..5702055 100644 --- a/django_downloadview/__init__.py +++ b/django_downloadview/__init__.py @@ -1,5 +1,5 @@ """django-downloadview provides generic download views for Django.""" -from django_downloadview.views import DownloadView +from django_downloadview.views import DownloadView, ObjectDownloadView #: Implement :pep:`396` diff --git a/django_downloadview/views.py b/django_downloadview/views.py index 8ecaf34..af739ba 100644 --- a/django_downloadview/views.py +++ b/django_downloadview/views.py @@ -1,23 +1,28 @@ from os.path import abspath, basename import shutil +from django.core.files import File from django.http import HttpResponse from django.views.generic.base import View +from django.views.generic.detail import BaseDetailView class DownloadMixin(object): file = None response_class = HttpResponse - def get_mime_type(self, file): - """Return mime-type of file.""" + def get_mime_type(self): + """Return mime-type of self.file.""" return 'application/octet-stream' - def render_to_response(self, file, **response_kwargs): + def render_to_response(self, **response_kwargs): """Returns a response with a file as attachment.""" - mime_type = self.get_mime_type(file) - absolute_filename = abspath(file) - filename = basename(file) + mime_type = self.get_mime_type() + if isinstance(self.file, File): + absolute_filename = self.file.name + 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: @@ -30,4 +35,13 @@ class DownloadMixin(object): class DownloadView(DownloadMixin, View): def get(self, request, *args, **kwargs): - return self.render_to_response(self.file) + return self.render_to_response() + + +class ObjectDownloadView(DownloadMixin, BaseDetailView): + file_attribute = 'file' + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + self.file = getattr(self.object, self.file_attribute) + return self.render_to_response()