Django: How do I download .xls file through a django view - python

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)

Related

Django excel export, file is not downloading

I am trying to perform excel export functionality in Django with xls. But When I am trying to perform that file is not downloading and there is no error also.
Here is my code.
def excelExport(request):
response = HttpResponse(content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment;filename="InitalRegistaration.xls"'
work_book = xlwt.Workbook(encoding='utf-8')
uc = u"".join(chr(0x0410 + i) for i in range(32)) # some Cyrillic characters
u8 = uc.encode("UTF-8")
work_sheet = work_book.add_sheet('Client Registration')
work_sheet.write(0,0,"Clients")
work_book.save(response)
return response
I don't know what's wrong with my code but the file is not getting downloaded nor there is the error coming from the code.
In python3 something like this should work:
from io import BytesIO
from tempfile import NamedTemporaryFile
with NamedTemporaryFile() as tmp:
work_book.save(tmp.name)
content = BytesIO(tmp.read())
response = HttpResponse(content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response['Content-Disposition'] = 'attachment; filename=%s' % dname
return response

Response ZIP file by Django

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

Python - create txt file on the fly and send it via FTP?

So i am currently creating a text file from a jinja2 template on the fly and having it be downloaded by the users browser, however i want to add an option to send it somewhere via FTP (all the FTP details are predefined and wont change)
how do i create the file to be sent?
Thanks
code:
...
device_config.stream(
STR = hostname,
IP = subnet,
BGPASNO = bgp_as,
LOIP = lo1,
DSLUSER = dsl_user,
DSLPASS = dsl_pass,
Date = install_date,
).dump(config_file)
content = config_file.getvalue()
content_type = 'text/plain'
content_disposition = 'attachment; filename=%s' % (file_name)
response = None
if type == 'FILE':
response = HttpResponse(content, content_type=content_type)
response['Content-Disposition'] = content_disposition
elif type == 'FTP':
with tempfile.NamedTemporaryFile() as temp:
temp.write(content)
temp.seek(0)
filename = temp.name
session = ftplib.FTP('192.168.1.1','test','password')
session.storbinary('STOR {0}'.format(file_name), temp)
session.quit()
temp.flush()
return response
EDIT
needed to add temp.seek(0) before sending the file
You can use the tempfile module to create a named temporary file.
import tempfile
with tempfile.NamedTemporaryFile() as temp:
temp.write(content)
temp.flush()
filename = temp.name
session.storbinary('STOR {0}'.format(file_name), temp)
Here is a working example using BytesIO under io module. Code is tested and works.
import ftplib
import io
session = ftplib.FTP('192.168.1.1','USERNAME','PASSWORD')
# session.set_debuglevel(2)
buf=io.BytesIO()
# b'str' to content of buff.write() as it throws an error in python3.7
buf.write(b"test string")
buf.seek(0)
session.storbinary("STOR testfile.txt",buf)
session.quit()

Python: generate xlsx in memory and stream file download?

for example the following code creates the xlsx file first and then streams it as a download but I'm wondering if it is possible to send the xlsx data as it is being created. For example, imagine if a very large xlsx file needs to be generated, the user has to wait until it is finished and then receive the download, what I'd like is to start the xlsx file download in the user browser, and then send over the data as it is being generated. It seems trivial with a .csv file but not so with an xlsx file.
try:
import cStringIO as StringIO
except ImportError:
import StringIO
from django.http import HttpResponse
from xlsxwriter.workbook import Workbook
def your_view(request):
# your view logic here
# create a workbook in memory
output = StringIO.StringIO()
book = Workbook(output)
sheet = book.add_worksheet('test')
sheet.write(0, 0, 'Hello, world!')
book.close()
# construct response
output.seek(0)
response = HttpResponse(output.read(), mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response['Content-Disposition'] = "attachment; filename=test.xlsx"
return response
Are you able to write tempfiles to disk while generating the XLSX?
If you are able to use tempfile you won't be memory bound, which is nice, but the download will still only start when the XLSX writer is done assembling the document.
If you can't write tempfiles, you'll have to follow this example http://xlsxwriter.readthedocs.org/en/latest/example_http_server.html and your code is unfortunately completely memory bound.
Streaming CSV is very easy, on the other hand. Here is code we use to stream any iterator of rows in a CSV response:
import csv
import io
def csv_generator(data_generator):
csvfile = io.BytesIO()
csvwriter = csv.writer(csvfile)
def read_and_flush():
csvfile.seek(0)
data = csvfile.read()
csvfile.seek(0)
csvfile.truncate()
return data
for row in data_generator:
csvwriter.writerow(row)
yield read_and_flush()
def csv_stream_response(response, iterator, file_name="xxxx.csv"):
response.content_type = 'text/csv'
response.content_disposition = 'attachment;filename="' + file_name + '"'
response.charset = 'utf8'
response.content_encoding = 'utf8'
response.app_iter = csv_generator(iterator)
return response
xlsx format is a zip file that contains several individual files, so you can't create it on the fly and send it out as it is being created.

Serving Excel(xlsx) file to the user for download in Django(Python)

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.

Categories

Resources