让Django提供可下载的文件

我希望网站上的用户能够下载路径被遮盖的文件,以便不能直接下载。

例如,我想要的URL是这样的,“ http://example.com/download/?f=somefile.txt

而在服务器上,我知道所有可下载文件驻留在“/ home / user / files /”文件夹中。

有没有办法使Django服务该文件下载,而不是试图找到一个URL和视图来显示它?

对于“两全其美”,您可以将S.Lott的解决方案与xsendfile模块结合起来:django生成文件路径(或文件本身),但实际的文件服务由Apache / Lighttpd处理。 一旦你设置了mod_xsendfile,与你的视图集成需要几行代码:

from django.utils.encoding import smart_str response = HttpResponse(mimetype='application/force-download') # mimetype is replaced by content_type for django 1.7 response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name) response['X-Sendfile'] = smart_str(path_to_file) # It's usually a good idea to set the 'Content-Length' header too. # You can also set any other required headers: Cache-Control, etc. return response 

当然,如果你已经控制了你的服务器,或者你的托管公司已经设置了mod_xsendfile,那么这只会起作用。

编辑:

mimetype被替换为django 1.7的content_type

 response = HttpResponse(content_type='application/force-download' 

编辑:对于nginx检查这个 ,它使用X-Accel-Redirect而不是apache X-Sendfile头。

“下载”只是一个HTTP头的变化。

请参阅http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file- attachments ,了解如何响应下载。

"/download"只需要一个URL定义。

请求的GETPOST字典将具有"f=somefile.txt"信息。

您的视图函数将简单地将基本路径与“ f ”值合并,打开文件,创建并返回响应对象。 它应该少于12行代码。

S.Lott拥有“好”/简单的解决方案,elo80ka拥有“最好”/高效的解决方案。 这是一个“更好的”/中间的解决方案 – 没有服务器设置,但对于大文件比天真的修复更高效:

http://djangosnippets.org/snippets/365/

基本上,Django仍然处理服务文件,但不会立即将所有内容加载到内存中。 这允许您的服务器(缓慢)提供大文件,而不会增加内存使用量。

同样,S.Lott的X-SendFile对于更大的文件仍然更好。 但是,如果你不能或不想为此烦恼,那么这个中间解决方案将会在没有麻烦的情况下获得更好的效率。

对于一个非常简单但不高效或可扩展的解决方案,您可以使用内置的django serve视图。 这对于快速原型或一次性工作来说是非常好的,但正如在这个问题中提到的那样,在生产中应该使用类似apache或nginx的东西。

 from django.views.static import serve filepath = '/some/path/to/local/file.txt' return serve(request, os.path.basename(filepath), os.path.dirname(filepath)) 

上面提到的是,mod_xsendfile方法不允许在文件名中使用非ASCII字符。

由于这个原因,我有一个可用于mod_xsendfile的补丁,只要名称被url编码,就可以发送任何文件,并附加头文件:

 X-SendFile-Encoding: url 

也发送。

http://ben.timby.com/?p=149

尝试@Rocketmonkeys解决方案,但下载的文件被存储为* .bin和给定的随机名称。 这当然不好。 从@ elo80ka添加另一行解决了这个问题。
这里是我现在使用的代码:

 filename = "/home/stackoverflow-addict/private-folder(not-porn)/image.jpg" wrapper = FileWrapper(file(filename)) response = HttpResponse(wrapper, content_type='text/plain') response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(filename) response['Content-Length'] = os.path.getsize(filename) return response 

您现在可以将文件存储在私人目录中(而不是在/ media或/ public_html中),并通过django将它们暴露给某些用户或在某些情况下。
希望它有帮助。

感谢@ elo80ka,@ S.Lott和@Rocketmonkeys的答案,得到了完美的解决方案相结合所有=)

只要提到Django 1.10中提供的FileResponse对象

试试: https : //pypi.python.org/pypi/django-sendfile/

“一旦Django检查了权限等,抽象文件上传到网络服务器(例如Apache与mod_xsendfile)。

您应该使用apachenginx等流行服务器在生产环境中提供的sendfile apis。 多年来,我使用这些服务器的sendfile API来保护文件。 然后创建一个简单的中间件基于django应用程序为此目的适合于开发和生产purpose.You可以访问源代码在这里 。
更新:在新版本中, python提供程序使用django FileResponse如果可用),还增加了从lighthttp,caddy到hiawatha的许多服务器实现的支持

用法

 pip install django-fileprovider 
  • 添加fileprovider应用程序INSTALLED_APPS设置,
  • fileprovider.middleware.FileProviderMiddleware添加到MIDDLEWARE_CLASSES设置
  • FILEPROVIDER_NAME设置设置为生产中的nginxapache ,默认情况下它是用于开发目的的python

在你的基于类或功能的视图中设置响应头X-File值为X-File绝对路径。 例如,

 def hello(request): // code to check or protect the file from unauthorized access response = HttpResponse() response['X-File'] = '/absolute/path/to/file' return response 

django-fileprovider程序的方式,你的代码将只需要最小的修改。

Nginx配置

要保护文件免受直接访问,您可以将配置设置为

  location /files/ { internal; root /home/sideffect0/secret_files/; } 

这里nginx设置一个位置url /files/只有访问内部,如果你使用上面的配置你可以设置X-File为,

 response['X-File'] = '/files/filename.extension' 

通过使用nginx配置,这个文件将被保护,您也可以从django views控制文件

Django建议您使用另一台服务器来提供静态介质(在同一台机器上运行的另一台服务器也可以)。他们建议使用lighttp等服务器。

这是非常简单的设置。 然而。 如果根据请求生成“somefile.txt”(内容是动态的),那么你可能希望Django提供它。

Django文档 – 静态文件

 def qrcodesave(request): import urllib2; url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0"; opener = urllib2.urlopen(url); content_type = "application/octet-stream" response = HttpResponse(opener.read(), content_type=content_type) response["Content-Disposition"]= "attachment; filename=aktel.png" return response 

另一个项目,看看: http: //readthedocs.org/docs/django-private-files/en/latest/usage.html看起来promissing,还没有测试它自己呢。

基本上这个项目会抽象出mod_xsendfile的配置,并允许你做如下的事情:

 from django.db import models from django.contrib.auth.models import User from private_files import PrivateFileField def is_owner(request, instance): return (not request.user.is_anonymous()) and request.user.is_authenticated and instance.owner.pk = request.user.pk class FileSubmission(models.Model): description = models.CharField("description", max_length = 200) owner = models.ForeignKey(User) uploaded_file = PrivateFileField("file", upload_to = 'uploads', condition = is_owner) 

我已经面对同样的问题多一次,所以使用xsendfile模块和auth视图装饰器实现django文件库 。 随意使用它作为您自己的解决方案的灵感。

https://github.com/danielsokolowski/django-filelibrary