views:

42

answers:

2

I'm trying to make a script for downloading uploaded files, on the user's machine. The problem is that the download simply doesn't work (it either downloads me an empty file, or gives me some errors).

the last error is: coercing to Unicode: need string or buffer, FieldFile found

def download_course(request, id):
    course = Courses.objects.get(pk = id).course

    path_to_file = 'root/cFolder'
    filename = course # Select your file here.                                
    wrapper = FileWrapper(file(course))
    content_type = mimetypes.guess_type(filename)[0]
    response = HttpResponse(wrapper, content_type = content_type)
    response['Content-Length'] = os.path.getsize(filename)
    response['Content-Disposition'] = 'attachment; filename=%s/' % smart_str(course)

    return response

how can i declare properly the filemane so that it will know each time what file to be donloading: the filename is actually 'course' as declared above

Thanks !

A: 

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 :)

Lakshman Prasad
now it says: 'FieldFile' object has no attribute '_default_manager'
dana
+1  A: 

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
nop, the name of the course is the correspondant of the 'course' field in the table
dana
hmm .. that's so weird cause my error is still coercing to Unicode: need string or buffer, FieldFile found . i really don;t understand why.
dana
Sorry, my answer was wrong, I checked again and edited. Now code above should work as expected and I tried to explain why it works that way.
cji
it works perfect !! just you forgotten to declare filename = course.name there.I have accepted the answer. Would you please post a link to your answer here too:http://stackoverflow.com/questions/3141682/django-download-file-empty (i've made a bounty, and i want to accept your answer there too. thnaks!)
dana
I edited one last time, to correct undeclared filename (I named that variable `path`, as I think it's more apropriate that way in this code). Glad I could help :)
cji