Django:在通用视图中提供下载

12 投票
4 回答
13978 浏览
提问于 2025-04-15 21:52

我想从一个文件夹里提供几个mp3文件,文件夹路径是/home/username/music。我本以为这没什么大不了的,但现在对如何使用通用视图和我自己的网址有点困惑。

这是我的urls.py文件:

url(r'^song/(?P<song_id>\d+)/download/$', song_download, name='song_download'),

我参考的例子在Django文档的通用视图部分可以找到:http://docs.djangoproject.com/en/dev/topics/generic-views/(在最底部)

我不太确定如何根据我的需求进行调整。以下是我的views.py文件:

def song_download(request, song_id):
    song = Song.objects.get(id=song_id)

    response = object_detail(
        request,
        object_id = song_id,
        mimetype = "audio/mpeg",
    )
    response['Content-Disposition'= "attachment; filename=%s - %s.mp3" % (song.artist, song.title)

    return response

我其实不知道怎么让它输出我的mp3文件,而不是现在这样输出一个包含当前页面HTML内容的.mp3文件。我的模板应该是我的mp3文件吗?我需要设置Apache来提供这些文件,还是Django可以从文件系统中获取mp3文件(当然需要正确的权限)并提供呢?如果确实需要配置Apache,我该怎么告诉Django呢?

提前谢谢你。这些文件都在硬盘上,所以我不需要即时“生成”任何东西,我也希望尽量不暴露这些文件的位置。如果能有一个简单的/song/1234/download就太好了。

4 个回答

1

用Django来提供静态文件并不是个好主意,建议使用Apache、nginx等服务器。

https://docs.djangoproject.com/en/dev/howto/static-files/deployment/

9

为了把我对Tomasz Zielinski的评论变成一个真正的回答:

有几个原因,确实让apache/nginx等服务器来处理文件传输会更好。大多数服务器都有一些机制来帮助处理这种情况:Apache和lighttpd有xsendfile,nginx有X-Accel-Redirect。

这个想法是,你可以使用django的所有功能,比如漂亮的网址、认证方法等等,但让服务器来负责发送文件。你的django视图需要做的,就是返回一个带有特殊头部的响应。然后服务器会用实际的文件替换这个响应。

以下是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
  • 安装 mode_xsendfile
  • 在你的apache配置中添加 XSendFileOn on 和(根据版本不同) XSendFileAllowAbove onXSendFilePath the/path/to/serve/from

这样你就不会暴露文件的位置,同时可以把所有的网址管理都留给django处理。

19

你为什么想用通用视图来做这个呢?其实不用通用视图也很简单:

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

我不太确定用通用视图是否能实现这个功能。不过无论如何,在这里使用通用视图都是多余的。因为没有模板可以渲染,通用视图自动提供的上下文就没什么用处了。

撰写回答