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

Python Django:在通用视图中提供下载服务,python,django,file,Python,Django,File,因此,我想从/home/username/music中的文件夹中提供一些MP3。我不认为这会有什么大不了的,但我有点困惑如何使用通用视图和我自己的url来实现它 url.py url(r'^song/(?P<song_id>\d+)/download/$', song_download, name='song_download'), 实际上,我不知道如何表达我希望它吐出我的mp3,而不是它现在所做的,即输出一个包含所有当前html页面的.mp3。我的模板应该是我的mp3吗?我是否需

因此,我想从
/home/username/music
中的文件夹中提供一些MP3。我不认为这会有什么大不了的,但我有点困惑如何使用通用视图和我自己的url来实现它

url.py

url(r'^song/(?P<song_id>\d+)/download/$', song_download, name='song_download'),
实际上,我不知道如何表达我希望它吐出我的mp3,而不是它现在所做的,即输出一个包含所有当前html页面的.mp3。我的模板应该是我的mp3吗?我是否需要设置apache来提供文件服务,或者Django是否能够从文件系统检索mp3(当然是正确的权限)并提供服务?如果它确实需要配置Apache,我该如何告诉Django


提前谢谢。这些文件都是高清的,所以我不需要在现场“生成”任何东西,如果可能的话,我想避免透露这些文件的位置。一个简单的/song/1234/下载就太棒了。

为什么要用一个通用视图来实现这一点?在没有常规视图的情况下,执行此操作非常容易:

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

我不确定是否有可能用一个通用的视图以某种方式实现这一点。但无论如何,在这里使用一个是多余的。由于没有要呈现的模板,通用视图自动提供的上下文是无用的。

使用Django提供静态文件是个坏主意,请使用Apache、nginx等


要将我对托马斯·齐林斯基的评论总结成一个真实的答案:

出于几个原因,让apache/nginx/etc来完成发送文件的工作确实更好。 大多数服务器都有在这种情况下提供帮助的机制:Apache和lighttpd有xsendfile,nginx有X-Accel-Redirect

其想法是,您可以使用django的所有特性,如漂亮的URL、身份验证方法等,但让服务器完成文件服务工作。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
  • 安装
  • 将上的
    XSendFileOn和(取决于版本)
    xsendfileallowoveron
    XSendFilePath/path/to/service/from
    添加到apache配置中

这样,您就不必重新显示文件位置,并将所有url管理都保留在django中。

好吧,该死,我想我太专注于让它与通用视图一起工作了,我甚至不认为我为什么需要它。正是我需要的,谢谢!mp3是二进制文件,所以使用文件读取模式“rb”而不是“r”,我到处寻找这个!谢谢你!我听说了,我完全支持使用apache,但是使用apache作为我的web服务器,我如何才能实现公认的答案呢?我想使用我自己的url,而不是透露我的下载url。我不是静态文件服务专家,但我打赌你也可以重写静态媒体url。我对上述链接的异议是“我们建议使用单独的Web服务器(即,不运行Django的服务器)来服务媒体。以下是一些不错的选择:”我听到他们响亮而清晰,但假设我有一个完整的路径和/或文件的url,我如何使用我上面提到的url样式吐出来?我试图找到开源的django项目,看看它们是如何做到的。你应该更关注Apache或NGIX配置和/或模块——它与在http服务器后面工作的django无关。那就是我。如果您遇到了完全相同的问题,请转到本页以找到答案。然而,你的回答根本解决不了问题。这只是一个网站链接,也不能解决这个问题。类似的东西可能会有所帮助:使用apache,modxsendfile,将“xsendfile on”“xsendfileallowovove on”添加到apache配置文件中,这样使用:
def song_下载(请求,song_id):response=HttpResponse()response['X-Sendfile']=smart_str(文件名)response['Content-Type']='audio/mpeg'response['Content-Length']=os.stat(filename).st_size返回响应
您可以使用os.path.getsize(pathToFile)而不是os.stat(path).st_size这是真正的交易,谢谢@xubntix!我喜欢你的解决方案,如果文件很大,django就不会在读取文件时陷入困境。这里的
smart\u str
的作用是什么更新:我现在明白了答案来自于旧的python 2天。我认为python3不再需要smart_str了。对吗?
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