Last active
February 10, 2017 21:11
-
-
Save henocdz/491bae4b291911510253067dab59267f to your computer and use it in GitHub Desktop.
A Django download HTTP response class that forces download in the browser.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from django.http import HttpResposne | |
| import os | |
| class DownloadResponse(HttpResponse): | |
| """ | |
| A download HTTP response class that forces download in the browser or redirects to URL given for file. | |
| Args: | |
| request (django.http.HttpRequest): We need this to send a `message.success` | |
| to client if the report is being generated | |
| when `path` callable returns `None` | |
| path (callable or str): A callable object that returns a path | |
| located in the local file system or a str object with the path | |
| filename (str): Given to the browser for the downloaded file | |
| redirect_to (str): Where to redirect the user if `path` callable returns `None` | |
| * (diverse): All configuration available for Django's HttpResponse class | |
| Kwargs: | |
| content_type (str): Tells the browser the type of file beign downloaded | |
| ** (diverse): All configuration available for Django's HttpResponse class | |
| """ | |
| def __init__(self, request, path, filename, redirect_to=None, *args, **kwargs): | |
| super(DownloadResponse, self).__init__(*args, **kwargs) | |
| if not hasattr(path, '__call__') and not isinstance(path, str): | |
| raise ValueError('DownloadResponse expects a callable object or str') | |
| # Convert to callable if it's a string | |
| self._get_path = path if hasattr(path, '__call__') else (lambda: path) | |
| self.path = self.get_path() | |
| self.filename = filename | |
| self.redirect_to = redirect_to or reverse('staff:reports') | |
| self.request = request | |
| self.get_response() | |
| def get_response(self): | |
| if self.path is None: | |
| self['Location'] = self.redirect_to | |
| self.status_code = 302 | |
| elif re.match('/tmp/', self.path): # force client to download attachment | |
| self.content = self.get_file_content() | |
| self['Content-Length'] = os.path.getsize(self.path) | |
| self['Content-Disposition'] = 'attachment; filename={}'.format(self.filename) | |
| elif re.match('https?://', self.path): # redirect client | |
| self['Location'] = self.path | |
| self.status_code = 302 | |
| def get_path(self): | |
| if not hasattr(self, '_path'): | |
| self._path = self._get_path() | |
| return self._path | |
| def get_file(self): | |
| if not hasattr(self, '_file'): | |
| self._file = open(self.path, 'rb') | |
| self._closable_objects.append(self._file) | |
| return self._file | |
| def get_file_content(self): | |
| return self.get_file().read() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment