Django download file not working

后端 未结 2 874
臣服心动
臣服心动 2020-12-17 05:32

I\'m trying to make a script for downloading the uploaded files, on the user\'s machine. The problem is that the download simply doesn\'t work (it either downloads me an emp

相关标签:
2条回答
  • 2020-12-17 06:07

    edited

    I think that you need to extract path value from FileField object:

    def download_course(request, id):
        course = Courses.objects.get(pk = id).course
    
        path = course.path # Get file path
        wrapper = FileWrapper( open( path, "r" ) )
        content_type = mimetypes.guess_type( path )[0]
    
        response = HttpResponse(wrapper, content_type = content_type)
        response['Content-Length'] = os.path.getsize( path ) # not FileField instance
        response['Content-Disposition'] = 'attachment; filename=%s/' % \ 
                                           smart_str( os.path.basename( path ) ) # same here
    
        return response
    

    Why is that:

    Let's say I have (well, I actually have) Model:

    class DanePracodawcy( DaneAdresowe, DaneKontaktowe ):
        # other fields
        logo = ImageWithThumbnailsField( upload_to = 'upload/logos/',
                                      thumbnail = {'size': (180, 90)},
                                      blank = True )
    

    ImageWithThumbnailsField is subclass of FileField, so it behaves the same way. Now, when I do SELECT:

    mysql> select logo from accounts_danepracodawcy;
    +-----------------------------+
    | logo                        |
    +-----------------------------+
    | upload/logos/Lighthouse.jpg |
    +-----------------------------+
    1 row in set (0.00 sec)
    

    it shows (relative to MEDIA_ROOT) path of stored file. But when I access logo Model attribute:

    [D:projekty/pracus]|1> from accounts.models import DanePracodawcy
    [D:projekty/pracus]|4> DanePracodawcy.objects.get().logo
                       <4> <ImageWithThumbnailsFieldFile: upload/logos/Lighthouse.jpg>
    [D:projekty/pracus]|5> type( _ )
                       <5> <class 'sorl.thumbnail.fields.ImageWithThumbnailsFieldFile'>
    

    I get instance of some object. If I try to pass that instance to os.path.getsize:

    [D:projekty/pracus]|8> import os.path
    [D:projekty/pracus]|9> os.path.getsize( DanePracodawcy.objects.get().logo )
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    
    D:\projekty\pracus\<ipython console> in <module>()
    
    C:\Python26\lib\genericpath.pyc in getsize(filename)
         47 def getsize(filename):
         48     """Return the size of a file, reported by os.stat()."""
    ---> 49     return os.stat(filename).st_size
         50
         51
    
    TypeError: coercing to Unicode: need string or buffer, ImageWithThumbnailsFieldFile found
    

    I get TypeError, like you. So I need file path as string, which can be obtained with path attribute:

    [D:projekty/pracus]|13> os.path.getsize(  DanePracodawcy.objects.get().logo.path )
                       <13> 561276L
    

    Alternatively, I could get name attribute and os.path.join it with MEDIA_ROOT setting:

    [D:projekty/pracus]|11> from django.conf import settings
    [D:projekty/pracus]|12> os.path.getsize(  os.path.join( settings.MEDIA_ROOT, DanePracodawcy.objects.get().logo.name ) )
                       <12> 561276L
    

    But that's unnecessary typing.

    Last thing to note: because path is absolute path, I need to extract filename to pass it to Content-Disposition header:

    [D:projekty/pracus]|16> DanePracodawcy.objects.get().logo.path
                       <16> u'd:\\projekty\\pracus\\site_media\\upload\\logos\\lighthouse.jpg'
    [D:projekty/pracus]|17> os.path.basename( DanePracodawcy.objects.get().logo.path )
                       <17> u'lighthouse.jpg'
    
    0 讨论(0)
  • 2020-12-17 06:21

    Unless you are letting the user download a dynamically generated file, I don't see why you need to do all that.

    You can just let this view redirect to the appropriate path, and the respective headers are set by the server serving the static files; typically apache or nginx

    I'd do your this view as follows:

    from django.conf import settings
    
    def download_course(request,id):
        course = get_object_or_404(Course,id=id)
        filename = course.course
        return redirect('%s/%s'%(settings.MEDIA_URL,filename))
    

    Enjoy :)

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