[Django]-Django download file not working

5👍

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'
👤cji

2👍

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 🙂

👤lprsd

Leave a comment