让Django提供可下载的文件

时间:2009-07-20 22:10:31

标签: python django download

我希望网站上的用户能够下载路径被遮挡的文件,因此无法直接下载。

例如,我希望网址是这样的,“http://example.com/download/?f=somefile.txt

在服务器上,我知道所有可下载的文件都位于文件夹“/ home / user / files /".

有没有办法让Django提供该文件供下载,而不是试图找到一个URL和View来显示它?

15 个答案:

答案 0 :(得分:184)

对于“两全其美”,你可以将S.Lott的解决方案与xsendfile module结合起来: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时才有效。

修改

  对于django 1.7,

mimetype被content_type替换

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

修改  对于nginx检查this,它使用X-Accel-Redirect而不是apache X-​​Sendfile标头。

答案 1 :(得分:85)

“下载”只是一个HTTP标题更改。

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

"/download"只需要一个网址定义。

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

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

答案 2 :(得分:27)

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

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

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

同样,对于较大的文件,S.Lott的X-SendFile仍然更好。但是如果你不能或者不想打扰它,那么这个中间解决方案可以让你获得更高的效率而不会有麻烦。

答案 3 :(得分:27)

对于非常简单的但效率不高或可扩展的解决方案,您只需使用内置的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))

答案 4 :(得分:15)

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

from wsgiref.util import FileWrapper
from django.http import HttpResponse

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的答案,得到了完美的解决方案,将所有这些结合起来=)

答案 5 :(得分:13)

上面提到mod_xsendfile方法不允许文件名中包含非ASCII字符。

出于这个原因,我有一个可用于mod_xsendfile的补丁,它允许发送任何文件,只要该名称是url编码的,以及附加标题:

X-SendFile-Encoding: url

也被发送。

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

答案 6 :(得分:13)

只提到Django 1.10中可用的FileResponse对象

编辑:在搜索通过Django流式传输文件的简单方法时,我遇到了自己的答案,所以这里有一个更完整的例子(对未来我来说)。它假定FileField名称为imported_file

views.py

from django.views.generic.detail import DetailView   
from django.http import FileResponse
class BaseFileDownloadView(DetailView):
  def get(self, request, *args, **kwargs):
    filename=self.kwargs.get('filename', None)
    if filename is None:
      raise ValueError("Found empty filename")
    some_file = self.model.objects.get(imported_file=filename)
    response = FileResponse(some_file.imported_file, content_type="text/csv")
    # https://docs.djangoproject.com/en/1.11/howto/outputting-csv/#streaming-large-csv-files
    response['Content-Disposition'] = 'attachment; filename="%s"'%filename
    return response

class SomeFileDownloadView(BaseFileDownloadView):
    model = SomeModel

urls.py

...
url(r'^somefile/(?P<filename>[-\w_\\-\\.]+)$', views.SomeFileDownloadView.as_view(), name='somefile-download'),
...

答案 7 :(得分:7)

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

一旦Django检查了权限等,就抽象将文件上传到web服务器(例如带有mod_xsendfile的Apache)。“

答案 8 :(得分:6)

您应该使用热门服务器提供的sendfile apis,例如apachenginx 在生产中。多年来我一直在使用这些服务器的sendfile api来保护文件。然后为此目的创建了一个简单的基于中间件的django app,适用于开发和开发。生产目的。您可以访问源代码here 更新:在新版本python提供程序中使用django FileResponse(如果可用),并且还添加了对lighthttp,caddy到hiawatha的许多服务器实现的支持

<强>用法

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

在基于类或函数的视图中将响应头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设置位置网址/files/仅访问internaly,如果您使用上述配置,则可以将X-File设置为,

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

通过nginx配置执行此操作,文件将受到保护&amp;你也可以从django views

控制文件

答案 9 :(得分:2)

Django建议你使用另一台服务器来提供静态媒体(在同一台机器上运行的另一台服务器也没问题。)他们建议使用lighttp等服务器。

设置起来非常简单。然而。如果'somefile.txt'是根据请求生成的(内容是动态的),那么你可能需要django来提供它。

Django Docs - Static Files

答案 10 :(得分:2)

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 

答案 11 :(得分:0)

另一个要查看的项目:http://readthedocs.org/docs/django-private-files/en/latest/usage.html 看起来很有希望,还没有自己测试过。

基本上,该项目抽象了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)

答案 12 :(得分:0)

我遇到了同样的问题,然后使用xsendfile模块和auth视图装饰器django-filelibrary实现了。随意使用它作为您自己的解决方案的灵感。

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

答案 13 :(得分:0)

答案 14 :(得分:0)

我为此做了一个项目。您可以看一下我的github仓库:

https://github.com/nishant-boro/django-rest-framework-download-expert

此模块提供了一种简单的方法来使用Apache模块Xsendfile在django rest框架中提供要下载的文件。它还具有一项附加功能,即仅向属于特定组的用户提供下载