Empty download file from django view - python

I am using django 1.11.2 and I want to have view with downloadable file. After click on link the file is downloading but file is empty and instead of png, I recieved empty txt file.
def download_file(request, uuid):
response = HttpResponse(content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(models.DownloadLink.objects.get(uuid=uuid).download_file.file)
response['Content-Length'] = 'http://{}{}'.format(Site.objects.get_current(), models.DownloadLink.objects.get(uuid=uuid).download_file.file.url)
return response
EDIT:
value here response['Content-Length'] is http://127.0.0.1:8000/media/filer_public/49/54/4954a7bb-8ad3-4679-9248-bffc7d186ca8/photo-105221.jpeg

Just pass the file in HttpResponse constructor like this:
def download_file(request, uuid):
file = models.DownloadLink.objects.get(uuid=uuid).download_file
response = HttpResponse(file.file, content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file.file)
response['Content-Length'] = 'http://{}{}'.format(Site.objects.get_current(), file.file.url)
return response
From HttpResponse docs
content should be an iterator or a string. If it’s an iterator, it
should return strings, and those strings will be joined together to
form the content of the response. If it is not an iterator or a
string, it will be converted to a string when accessed.

Related

Serving .json file to download

I am trying to serve a .json file through this function. The problem is that every time I make the request the browser displays the content instead of downloading the file.
I think it could be due to the fact that I am using .read() as a parameter for the HttpResponse object constructor. However, if I use only the file object, I get the following exception:
TypeError: cannot serialize '_io.BufferedRandom' object
Code
try:
invoices = models.Invoice.objects.filter(pk__in=document_ids).order_by(*ordering)
pcustomers = models.CustomerProxy.objects.all()
mixed_query = list(invoices) + list(pcustomers)
file = tempfile.NamedTemporaryFile(suffix='.json')
file.write(serializers.serialize('json', mixed_query).encode())
file.seek(0)
response = HttpResponse(file.read(), content_type='application/json')
response['Content-Disposition'] = 'attachment; filename=%s' % file.name
response['Content-Length'] = os.path.getsize(file.name)
except Exception:
raise
return response
You don't need to go through the whole file generation process to create a downloadable file, you just need to add the Content-Disposition header normally. Does the code below work?
...
mixed_query = list(invoices) + list(pcustomers)
json_str = serializers.serialize('json', mixed_query))
response = HttpResponse(json_str, content_type='application/json')
response['Content-Disposition'] = 'attachment; filename=export.json'
Based on the code that you show, you do not need to write to a temporary file. Why don't you just pass the result of serialize() into HttpResponse()?
response = HttpResponse(serializers.serialize('json', mixed_query), content_type='application/json')
You can set the attachment name to whatever you like, something descriptive would seem to be better than the random alphanumeric string generated by tempfile.NamedTemporaryFile().
response['Content-Disposition'] = 'attachment; filename="invoices_and_customers.json"'
If you really want to specify the length:
response['Content-Length'] = len(response.content)
or you could add the ConditionalGetMiddleware middleware to your settings and have Django add the Content-Length for you.
add this to your Http response
HttpResponse(mimetype='application/force-download')

Django - Error downloading image

I am developing a function to download an image.
but I am getiing this error
coercing to Unicode: need string or buffer, ImageFieldFile found
It's the code:
def download_image(request, image_id):
img = Base.objects.get(base_id=image_id)
wrapper = FileWrapper(open(img.file)) # img.file returns full path to the image
content_type = mimetypes.guess_type(filename)[0] # Use mimetypes to get file type
response = HttpResponse(wrapper,content_type=content_type)
response['Content-Length'] = os.path.getsize(img.file)
response['Content-Disposition'] = "attachment; filename=%s" % img.name
return response
img.file is a ImageFieldFile object, open() requires a string. You need to do open(img.file.name) to get the actual file path.

how to serve downloadable zip file in django

Im going over the django documentation and I found this piece of code that allows you to render a file as attachment
dl = loader.get_template('files/foo.zip')
context = RequestContext(request)
response = HttpResponse(dl.render(context), content_type = 'application/force-download')
response['Content-Disposition'] = 'attachment; filename="%s"' % 'foo.zip'
return response
The foo.zip file was created using pythons zipfile.ZipFile().writestr method
zip = zipfile.ZipFile('foo.zip', 'a', zipfile.ZIP_DEFLATED)
zipinfo = zipfile.ZipInfo('helloworld.txt', date_time=time.localtime(time.time()))
zipinfo.create_system = 1
zip.writestr(zipinfo, StringIO.StringIO('helloworld').getvalue())
zip.close()
But when I tried the code above to render the file, Im getting this error
'utf8' codec can't decode byte 0x89 in position 10: invalid start byte
Any suggestions on how to do this right?
I think what you want is to serve a file for people to download it. If that's so, you don't need to render the file, it's not a template, you just need to serve it as attachment using Django's HttpResponse:
zip_file = open(path_to_file, 'r')
response = HttpResponse(zip_file, content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename="%s"' % 'foo.zip'
return response
FileResponse is preferred over HttpResponse for binary files. Also, opening the file in 'rb' mode prevents UnicodeDecodeError.
zip_file = open(path_to_file, 'rb')
return FileResponse(zip_file)

How to download a file uploaded using django-filebrowser?

I am trying to create a download of a file object. the file was added using django-filebrowser which means it is turn in to a string path to the the file. I have tried the following:
f = Obj.objects.get(id=obj_id)
myfile = FileObject(os.path.join(MEDIA_ROOT, f.Audio.path))
...
response = HttpResponse(myfile, content_type="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
The file that is downloaded contains the string of the path to the file location and not the file. Could anyone be of assistance on how to access the file object?
f = Obj.objects.get(id=obj_id)
myfile = open(os.path.join(MEDIA_ROOT, f.Audio.path)).read()
...
response = HttpResponse(myfile, content_type="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
NOTE! This is not memory friendly! Since the whole file is put into memory. You're better of using a webserver for file serving or if you want to use Django for file serving you could use xsendfile or have a look at this thread
You need to open the file and send it's binary contents back in the response. So something like:
fileObject = FileObject(os.path.join(MEDIA_ROOT, f.Audio.path))
myfile = open(fileObject.path)
response = HttpResponse(myfile.read(), mimetype="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
Hope that gets what you're looking for.

How to save file data from POST variable and load it back to response in Python Django?

I have a such problem - I am using Python 2.6 / Django 1.3 and I need to accept as POST variable with key 'f', which contains a binary data. After that, I need to save data in a file.
POST
T$topX$objectsX$versionY$archiverО©ҐR$0О©ҐО©ҐО©Ґull_=<---------------------- content of file -------------------->О©ҐО©Ґ_NSKeyedArchive(258:=CО©ҐО©Ґ
Code
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
def save(request):
upload_file = request.POST['f']
save_path = default_storage.save('%s%s' % (save_dir, filename),
ContentFile(upload_file))
When I am trying to do
nano /tmp/myfile.zip
It returns data like
T^#^#^#$^#^#^#t^#^#^#o^#^#^#p^#^#^#X^#^#^#$^#^#^#o^#^#^#b^#^#^#j^#^#^#e^#^#^#c^#^#^#t^#^#^#s^#^#^#X^#^#^#$^#^#^#v^#^#^#e^#^#^#r^#^#^#s^#^#^#i^#^#$
When its done, I am going to read saved file
def read(request):
user_file = default_storage.open(file_path).read()
file_name = get_filename(file_path)
response = HttpResponse(user_file, content_type = 'text/plain',
mimetype = 'application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % file_name
response['Content-Length'] = default_storage.size(file_path)
return response
In case, when I am writing
print user_file
It returns a correct data, but when I am returning a HttpResponse it has a different data from a source
It would probably be easier, and more memory efficient if you just save the data into a file, and like #keckse said, let a browser stream it. Django is very inefficient in streaming data. It will all depend on the size of the data. If you want to stream it with django anyways, it can be done like this:
from django.http import HttpResponse
import os.path
import mimetypes
def stream(request, document, type=None):
doc = Document.objects.get(pk=document)
fsock = open(doc.file.path,"r")
file_name = os.path.basename(doc.file.path)
mime_type_guess = mimetypes.guess_type(file_name)
if mime_type_guess is not None:
response = HttpResponse(fsock, mimetype=mime_type_guess[0])
response['Content-Disposition'] = 'attachment; filename=' + file_name
return response
In your case you might want to set the mime type manually, you can try out application/octet-stream too. The mainpassing iterators difference is that you pass the "string" from file.read(), instead of the handle to the file directly. Please note: if you use read(), you will be loading the whole file into memory.
More on passing iterators to HttpResonse. And I might be wrong, but I think you can drop the content-type.

Categories