19👍
Why do you want to do this with a generic view? It’s very easy to do this without generic views:
from django.http import HttpResponse
def song_download(request, song_id):
song = Song.objects.get(id=song_id)
fsock = open('/path/to/file.mp3', 'rb')
response = HttpResponse(fsock, content_type='audio/mpeg')
response['Content-Disposition'] = "attachment; filename=%s - %s.mp3" % \
(song.artist, song.title)
return response
I’m not sure if it’s possible to make this work somehow with a generic view. But either way, using one is redundant here. With no template to render, the context that is automatically provided by the generic view is useless.
9👍
To wrap my comment to Tomasz Zielinski into a real answer:
For several reasons it is indeed better to let apache/nginx/etc do the work of sending files.
Most servers have mechanisms to help in that usecase: Apache and lighttpd have xsendfile, nginx has X-Accel-Redirect.
The idea is that you can use all the features of django like nice urls, authentification methods, etc, but let the server do the work of serving files. What your django view has to do, is to return a response with a special header. The server will then replace the response with the actual file.
Example for apache:
def song_download(request):
path = '/path/to/file.mp3'
response = HttpResponse()
response['X-Sendfile'] = smart_str(path)
response['Content-Type'] = "audio/mpeg"
response['Content-Length'] = os.stat(path).st_size
return response
- install mode_xsendfile
- add
XSendFileOn on
and (depending on the version)XSendFileAllowAbove on
orXSendFilePath the/path/to/serve/from
to your apache configuration.
This way you don’t reveale the file location, and keep all the url management in django.
- Testing authentication in Django Rest Framework Views — Cannot authenticate when testing
- Django South Error: "there is no enabled application matching 'myapp'"
- Does django-rest-swagger not work well with modelserializers?
- Django translations does not work
- Adding commas to numbers when typing
1👍
Serving static files with Django is a bad idea, use Apache, nginx etc.
https://docs.djangoproject.com/en/dev/howto/static-files/deployment/
- When I use Django Celery apply_async with eta, it does the job immediately
- Django – inlineformset_factory with more than one ForeignKey
- Experiences of creating Social Network site in Django
- PyCharm include and modify External library in project
- Default_if_none requires 2 arguments, 1 provided
1👍
To answer the original question how to use a generic view, you could do the following:
from django.views.generic import DetailView
from django.http.response import FileResponse
class DownloadSong(DetailView):
model = Song
def get(self, request, *args, **kwargs):
super().get(request, *args, **kwargs)
song = self.object
return FileResponse(open(song, 'rb'),
as_attachment=True,
filename=f'{song.artist} - {song.title}.mp3')
Docs:
- Detailview: https://docs.djangoproject.com/en/3.2/ref/class-based-views/generic-display/#detailview
- FileResponse: https://docs.djangoproject.com/en/3.2/ref/request-response/#fileresponse-objects
If your Django version does not have the FileResponse
object, use the HttpResponse
as shown in the other answers.