Having Django serve downloadable files

2018-12-31 08:19发布

I want users on the site to be able to download files whose paths are obscured so they cannot be directly downloaded.

For instance, I'd like the URL to be something like this, "http://example.com/download/?f=somefile.txt

And on the server, I know that all downloadable files reside in a folder "/home/user/files/".

Is there a way to make Django serve that file for download as opposed to trying to find a URL and View to display it?

14条回答
残风、尘缘若梦
2楼-- · 2018-12-31 08:40
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 
查看更多
人间绝色
3楼-- · 2018-12-31 08:41

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

"Abstraction to offload file uploads to web-server (e.g. Apache with mod_xsendfile) once Django has checked permissions etc."

查看更多
姐姐魅力值爆表
4楼-- · 2018-12-31 08:46

A "download" is simply an HTTP header change.

See http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment for how to respond with a download.

You only need one URL definition for "/download".

The request's GET or POST dictionary will have the "f=somefile.txt" information.

Your view function will simply merge the base path with the "f" value, open the file, create and return a response object. It should be less than 12 lines of code.

查看更多
无与为乐者.
5楼-- · 2018-12-31 08:46

Tried @Rocketmonkeys solution but downloaded files were being stored as *.bin and given random names. That's not fine of course. Adding another line from @elo80ka solved the problem.
Here is the code I'm using now:

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

You can now store files in a private directory (not inside /media nor /public_html) and expose them via django to certain users or under certain circumstances.
Hope it helps.

Thanks to @elo80ka, @S.Lott and @Rocketmonkeys for the answers, got the perfect solution combining all of them =)

查看更多
深知你不懂我心
6楼-- · 2018-12-31 08:47

S.Lott has the "good"/simple solution, and elo80ka has the "best"/efficient solution. Here is a "better"/middle solution - no server setup, but more efficient for large files than the naive fix:

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

Basically, Django still handles serving the file but does not load the whole thing into memory at once. This allows your server to (slowly) serve a big file without ramping up the memory usage.

Again, S.Lott's X-SendFile is still better for larger files. But if you can't or don't want to bother with that, then this middle solution will gain you better efficiency without the hassle.

查看更多
呛了眼睛熬了心
7楼-- · 2018-12-31 08:49
登录 后发表回答