I am trying to compress data with pyminizip and return the data as response in a Django project as follows
def get_csv_file(request):
response = HttpResponse(content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="member.zip"'
users = User.objects.all()
file_path = os.path.join(tempfile.gettempdir(), 'member.csv')
f = open(file_path, 'w')
file_writer = csv.writer(f, quotechar='"', quoting=csv.QUOTE_MINIMAL)
for user in users:
file_writer.writerow([user.username, user.email])
f.close()
pyminizip.compress(file_path, "members", response, "pass", int(1))
return response
getting this error
ValueError at /get_csv_file/
expected arguments are compress(srcfile, prefix, zipfile, password, compress_level)
The "zipfile" argument in the pyminizip.compress function is expecting a file path to write a zip file, howeer you've supplied a HttpResponse object, so it doesn't know what to do with it.
You'll need to temporarily write the file to disk, and then read it to be able to send it back
Related
I have a button which downloads a excel file with extension .xls. I am using module xlrd to parse the file and return it back to the user. However it appears to add the object name into the excel file instead of the data.
How can I return the file to the user with the data rather than the objects name?
View
def download_file(self, testname):
import csv, socket, os, xlrd
extension = '.xls'
path = r"C:\tests\{}_Report{}".format(testname, extension)
try:
f = xlrd.open_workbook(path)
response = HttpResponse(f, content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename={}_Report{}'.format(testname, extension)
return response
except Exception as Error:
return HttpResponse(Error)
return redirect('emissions_dashboard:overview_view_record')
Excel result
Download successful:
Content:
Note: I understand this is an old file format but is required for this particular project.
You are trying to send a xlrd.book.Book object, not a file.
You used xlrd to do your things in the workbook, and then saved to a file.
workbook = xlrd.open_workbook(path)
#... do something
workbook.save(path)
Now you send it like any other file:
with open(path, 'rb') as f:
response = HttpResponse(f.read(), content_type="application/ms-excel")
response['Content-Disposition'] = 'attachment; filename={}_Report{}'.format(testname, extension)
I try to download img from url, add it to zip archive and then response this archive by Django HttpResponse.
import os
import requests
import zipfile
from django.http import HttpResponse
url = 'http://some.link/img.jpg'
file = requests.get(url)
data = file.content
rf = open('tmp/pic1.jpg', 'wb')
rf.write(data)
rf.close()
zipf = zipfile.ZipFile('tmp/album.zip', 'w') # This file is ok
filename = os.path.basename(os.path.normpath('tmp/pic1.jpg'))
zipf.write('tmp/pic1.jpg', filename)
zipf.close()
resp = HttpResponse(open('tmp/album.zip', 'rb'))
resp['Content-Disposition'] = 'attachment; filename=album.zip'
resp['Content-Type'] = 'application/zip'
return resp # Got corrupted zip file
When I save file to tmp folder - it's ok, I can extract it.
But when I response this file I get 'Error 1/2/21' on MacOS or Unexpected EOF if I try to open in Atom editor (just for test).
I also used StringIO instead of saving zip file, but it doesn't influence the result.
If you're using Python 3, you'd do it like this:
import os, io, zipfile, requests
from django.http import HttpResponse
# Get file
url = 'https://some.link/img.jpg'
response = requests.get(url)
# Get filename from url
filename = os.path.split(url)[1]
# Create zip
buffer = io.BytesIO()
zip_file = zipfile.ZipFile(buffer, 'w')
zip_file.writestr(filename, response.content)
zip_file.close()
# Return zip
response = HttpResponse(buffer.getvalue())
response['Content-Type'] = 'application/x-zip-compressed'
response['Content-Disposition'] = 'attachment; filename=album.zip'
return response
That's without saving the file. Downloaded file goes directly to io.
To response saved file, use this syntax:
response = HttpResponse(open('path/to/file', 'rb').read())
def download(request):
f = open("next_op.xls")
data = f.read()
f.close()
response = HttpResponse(data, content_type = './application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="nextop.xls"'
return response
When I use this code, I can download the file correctly, but the file name is invalid. I get the file name "download", and I found the response header doesn't include the Content-Disposition after I download the file.
you may need this:
fd = open(file, 'rb')
return FileResponse(fd, as_attachment=True, filename='xxx')
I'm trying create and serve excel files using Django. I have a jar file which gets parameters and produces an excel file according to parameters and it works with no problem. But when i'm trying to get the produced file and serve it to the user for download the file comes out broken. It has 0kb size. This is the code piece I'm using for excel generation and serving.
def generateExcel(request,id):
if os.path.exists('./%s_Report.xlsx' % id):
excel = open("%s_Report.xlsx" % id, "r")
output = StringIO.StringIO(excel.read())
out_content = output.getvalue()
output.close()
response = HttpResponse(out_content,content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
args = ['ServerExcel.jar', id]
result = jarWrapper(*args) # this creates the excel file with no problem
if result:
excel = open("%s_Report.xlsx" % id, "r")
output = StringIO.StringIO(excel.read())
out_content = output.getvalue()
output.close()
response = HttpResponse(out_content,content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
return HttpResponse(json.dumps({"no":"excel","no one": "cries"}))
I have searched for possible solutions and tried to use File Wrapper also but the result did not changed. I assume i have problem with reading the xlsx file into StringIO object. But dont have any idea about how to fix it
Why on earth are you passing your file's content to a StringIO just to assign StringIO.get_value() to a local variable ? What's wrong with assigning file.read() to your variable directly ?
def generateExcel(request,id):
path = './%s_Report.xlsx' % id # this should live elsewhere, definitely
if os.path.exists(path):
with open(path, "r") as excel:
data = excel.read()
response = HttpResponse(data,content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
# quite some duplication to fix down there
Now you may want to check weither you actually had any content in your file - the fact that the file exists doesn't mean it has anything in it. Remember that you're in a concurrent context, you can have one thread or process trying to read the file while another (=>another request) is trying to write it.
In addition to what Bruno says, you probably need to open the file in binary mode:
excel = open("%s_Report.xlsx" % id, "rb")
You can use this library to create excel sheets on the fly.
http://xlsxwriter.readthedocs.io/
For more information see this page. Thanks to #alexcxe
XlsxWriter object save as http response to create download in Django
my answer is:
def generateExcel(request,id):
if os.path.exists('./%s_Report.xlsx' % id):
with open('./%s_Report.xlsx' % id, "rb") as file:
response = HttpResponse(file.read(),content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
# quite some duplication to fix down there
why using "rb"? because HttpResponse class init parameters is (self, content=b'', *args, **kwargs), so we should using "rb" and using .read() to get the bytes.
I have a view that takes data from my site and then makes it into a zip compressed csv file. Here is my working code sans zip:
def backup_to_csv(request):
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=backup.csv'
writer = csv.writer(response, dialect='excel')
#code for writing csv file go here...
return response
and it works great. Now I want that file to be compressed before it gets sent out. This is where I get stuck.
def backup_to_csv(request):
output = StringIO.StringIO() ## temp output file
writer = csv.writer(output, dialect='excel')
#code for writing csv file go here...
response = HttpResponse(mimetype='application/zip')
response['Content-Disposition'] = 'attachment; filename=backup.csv.zip'
z = zipfile.ZipFile(response,'w') ## write zip to response
z.writestr("filename.csv", output) ## write csv file to zip
return response
But thats not it and I have no idea how to do this.
OK I got it. Here is my new function:
def backup_to_csv(request):
output = StringIO.StringIO() ## temp output file
writer = csv.writer(output, dialect='excel')
#code for writing csv file go here...
response = HttpResponse(mimetype='application/zip')
response['Content-Disposition'] = 'attachment; filename=backup.csv.zip'
z = zipfile.ZipFile(response,'w') ## write zip to response
z.writestr("filename.csv", output.getvalue()) ## write csv file to zip
return response
Note how, in the working case, you return response... and in the NON-working case you return z, which is NOT an HttpResponse of course (while it should be!).
So: use your csv_writer NOT on response but on a temporary file; zip the temporary file; and write THAT zipped bytestream into the response!
zipfile.ZipFile(response,'w')
doesn't seem to work in python 2.7.9. The response is a django.HttpResponse object (which is said to be file-like) but it gives an error "HttpResponse object does not have an attribute 'seek'. When the same code is run in python 2.7.0 or 2.7.6 (I haven't tested it in other versions) it is OK... So you'd better test it with python 2.7.9 and see if you get the same behaviour.