Reputation: 43096
I have the following code for managing file download through django.
def serve_file(request, id):
file = models.X.objects.get(id=id).file #FileField
file.open('rb')
wrapper = FileWrapper(file)
mt = mimetypes.guess_type(file.name)[0]
response = HttpResponse(wrapper, content_type=mt)
import unicodedata, os.path
filename = unicodedata.normalize('NFKD', os.path.basename(file.name)).encode("utf8",'ignore')
filename = filename.replace(' ', '-') #Avoid browser to ignore any char after the space
response['Content-Length'] = file.size
response['Content-Disposition'] = 'attachment; filename={0}'.format(filename)
#print response
return response
Unfortunately, my browser get an empty file when downloading.
The printed response seems correct:
Content-Length: 3906
Content-Type: text/plain
Content-Disposition: attachment; filename=toto.txt
blah blah ....
I have similar code running ok. I don't see what can be the problem. Any idea?
PS: I have tested the solution proposed here and get the same behavior
Update:
Replacing wrapper = FileWrapper(file)
by wrapper = file.read()
seems to fix the problem
Update: If I comment the print response
, I get similar issue:. the file is empty. Only difference: FF detects a 20bytes size. (the file is bigger than this)
Upvotes: 2
Views: 2208
Reputation: 14487
From django documentation:
FieldFile.open(mode='rb') Behaves like the standard Python open() method and opens the file associated with this instance in the mode specified by mode.
If it works like pythons open
then it should return a file-object, and should be used like this:
f = file.open('rb')
wrapper = FileWrapper(f)
Upvotes: 0
Reputation: 596723
File object is an interable, and a generator. It can be read only once before being exausted. Then you have to make a new one, of use a method to start at the begining of the object again (e.g: seek()
).
read()
returns a string, which can be read multiple times without any problem, this is why it solves your issue.
So just make sure that if you use a file like object, you don't read it twice in a row. E.G: don't print it, then returns it.
Upvotes: 1