Having Django serve downloadable files

后端 未结 15 1565
野的像风
野的像风 2020-11-22 05:46

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

相关标签:
15条回答
  • 2020-11-22 06:36

    I did a project on this. You can look at my github repo:

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

    This module provides a simple way to serve files for download in django rest framework using Apache module Xsendfile. It also has an additional feature of serving downloads only to users belonging to a particular group

    0 讨论(0)
  • 2020-11-22 06:37

    For the "best of both worlds" you could combine S.Lott's solution with the xsendfile module: django generates the path to the file (or the file itself), but the actual file serving is handled by Apache/Lighttpd. Once you've set up mod_xsendfile, integrating with your view takes a few lines of code:

    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
    

    Of course, this will only work if you have control over your server, or your hosting company has mod_xsendfile already set up.

    EDIT:

    mimetype is replaced by content_type for django 1.7

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

    EDIT: For nginx check this, it uses X-Accel-Redirect instead of apache X-Sendfile header.

    0 讨论(0)
  • 2020-11-22 06:37

    Another project to have a look at: http://readthedocs.org/docs/django-private-files/en/latest/usage.html Looks promissing, haven't tested it myself yet tho.

    Basically the project abstracts the mod_xsendfile configuration and allows you to do things like:

    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)
    
    0 讨论(0)
  • 2020-11-22 06:44

    Just mentioning the FileResponse object available in Django 1.10

    Edit: Just ran into my own answer while searching for an easy way to stream files via Django, so here is a more complete example (to future me). It assumes that the FileField name is 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'),
    ...
    
    0 讨论(0)
  • 2020-11-22 06:45

    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.

    0 讨论(0)
  • 2020-11-22 06:46

    It was mentioned above that the mod_xsendfile method does not allow for non-ASCII characters in filenames.

    For this reason, I have a patch available for mod_xsendfile that will allow any file to be sent, as long as the name is url encoded, and the additional header:

    X-SendFile-Encoding: url
    

    Is sent as well.

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

    0 讨论(0)
提交回复
热议问题