让 Django 提供可下载文件

2024-12-23 08:43:00
admin
原创
81
摘要:问题描述:我希望网站上的用户能够下载路径被隐藏的文件,这样就无法直接下载。例如,我希望 URL 如下所示:http://example.com/download/?f=somefile.txt并且在服务器上,我知道所有可下载的文件都位于文件夹中/home/user/files/。有没有办法让 Django 提...

问题描述:

我希望网站上的用户能够下载路径被隐藏的文件,这样就无法直接下载。

例如,我希望 URL 如下所示:http://example.com/download/?f=somefile.txt

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

有没有办法让 Django 提供该文件供下载,而不是尝试找到 URL 并查看它?


解决方案 1:

为了“两全其美”,您可以将 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 时才会起作用。

编辑:

对于 django 1.7,mimetype 已被 content_type 取代

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

编辑:
为了nginx检查这一点,它使用X-Accel-Redirect而不是apacheX-Sendfile 标头。

解决方案 2:

“下载”仅仅是 HTTP 标头的改变。

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

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

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

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

解决方案 3:

对于非常简单但不高效或不可扩展的解决方案,您可以只使用内置的 djangoserve视图。这对于快速原型或一次性工作非常有用,但正如本问题中提到的那样,您应该在生产中使用 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:

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

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

基本上,Django 仍负责提供文件,但不会一次性将整个文件加载到内存中。这样,您的服务器就可以(缓慢地)提供大文件,而不会增加内存使用量。

再次强调,S.Lott 的 X-SendFile 仍然更适合处理较大的文件。但是,如果您不能或不想为此烦恼,那么这个中间解决方案将为您带来更高的效率,而不会带来麻烦。

解决方案 5:

只需提及Django 1.10 中可用的FileResponse对象

编辑:在搜索通过 Django 传输文件的简单方法时,我偶然发现了自己的答案,因此这里有一个更完整的示例(对未来的我来说)。它假设 FileField 名称是imported_file

视图.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'),
...

解决方案 6:

尝试了 @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 提供的答案,结合所有这些答案,得到了完美的解决方案 =)

解决方案 7:

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

出于这个原因,我为 mod_xsendfile 提供了一个补丁,该补丁允许发送任何文件,只要名称是 url 编码的,并且附加标题为:

X-SendFile-Encoding: url

也發送了。

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

解决方案 8:

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

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

解决方案 9:

您应该在生产中使用流行服务器(如apache或 )提供的 sendfile api。多年来,我一直使用这些服务器的 sendfile api 来保护文件。然后为此创建了一个简单的基于中间件的 django 应用程序,适用于开发和生产目的。您可以在此处nginx访问源代码。

更新:在新版本中,python提供程序使用 django(FileResponse如果可用),并且还增加了对从 lighthttp、caddy 到 hiawatha 的许多服务器实现的支持

用法

pip install django-fileprovider
  • 将应用程序添加fileproviderINSTALLED_APPS设置,

  • 添加fileprovider.middleware.FileProviderMiddlewareMIDDLEWARE_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/,如果您使用上述配置,您可以X-File这样设置:

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

通过使用 nginx 配置,该文件将受到保护,并且您还可以从 django 控制该文件views

解决方案 10:

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:

Django 建议您使用另一台服务器来提供静态媒体(在同一台机器上运行的另一台服务器也可以)。他们建议使用诸如lighttp之类的服务器。

设置起来非常简单。但是,如果“somefile.txt”是根据请求生成的(内容是动态的),那么您可能希望 django 为其提供服务。

Django 文档 - 静态文件

解决方案 12:

另一个值得一看的项目: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)

解决方案 13:

我不止一次遇到过同样的问题,因此使用 xsendfile 模块和 auth 视图装饰器django-filelibrary实现了这个问题。请随意使用它作为您自己的解决方案的灵感。

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

解决方案 14:

使用https://github.com/johnsensible/django-sendfile提供对静态 html 文件夹的受保护访问: https: //gist.github.com/iutinvg/9907731

解决方案 15:

我做了一个关于这个的项目。你可以看看我的 github repo:

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

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

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1120  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   75  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   66  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   76  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   70  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用