I am using openpylx to create a spreadsheet and return it in an HttpResponse object in Django (1.7). Currently, this is working except that the spreadsheet is not downloaded; it is displayed in the browser as a bunch of characters (pic related).
Here is my code:
from openpyxl import Workbook
from openpyxl.writer.excel import save_virtual_workbook
workbook = Workbook()
...
#Create the workbook here
...
filestream = save_virtual_workbook(workbook)
response = HttpResponse(filestream,
content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="my_sheet.xlsx"'
return response
This code is pretty much identical to several other solutions offered in other questions here on SO. Unfortunately, I can't figure out what the difference is. Maybe Django version?
I know that I am missing someething stupid here. What is it?
EDIT:
I know that the issue is not with the spreadsheet itself. If I save the page with the characters as "my_sheet.xlsx", then open it in Excel, all of the proper data is present.
Related
Right now I am doing the following.
import xlrd
resp = requests.get(url, auth=auth).content
output = open(r'temp.xlsx', 'wb')
output.write(resp)
output.close()
xl = xlrd.open_workbook(r'temp.xlsx')
sh = 1
try:
for sheet in xl.sheets():
xls.append(sheet.name)
except:
xls = ['']
It's extracting the sheets but I don't know how to read the file or if saving the file as an .xlsx is actually working for macros. All I know is that the code is not working right now and I need to be able to catch the data that is being generated in a macro. Please help! Thanks.
I highly recommend using xlwings if you want to open, modify, and save .xlsm files without corrupting them. I have tried a ton of different methods (using other modules like openpyxl) and the macros always end up being corrupted.
import xlwings as xw
app = xw.App(visible=False) # IF YOU WANT EXCEL TO RUN IN BACKGROUND
xlwb = xw.Book('PATH\\TO\\FILE.xlsm')
xlws = {}
xlws['ws1'] = xlwb.sheets['Your Worksheet']
print(xlws['ws1'].range('B1').value) # get value
xlws['ws1'].range('B1').value = 'New Value' # change value
yourMacro = xlwb.macro('YourExcelMacro')
yourMacro()
xlwb.save()
xlwb.close()
Edit - I added an option to keep Excel invisible at users request
I am working on automating an Excel file which is linked to certain .csv files.
Those .csv files are created from a SAS Code which is run every Quarter.
The files created are timestamped accordingly for example XYZ_201603.csv and XYZ_201606.csv and so on.
I need to update the links on my Excel File so that it automatically changes the link to the file from next quarter. I am trying to do this using Python win32com.client and my code looks like
from win32com import Dispatch
xl_app = Dispatch("Excel.Application")
xl_app.Visible = True
xl_app.DisplayAlerts = False
wb = xl_app.workbooks.open(r"C:\Users\XYZ\Desktop\Test\Summary.xlsx")
xl_app.AskToUpdateLinks = False
try:
wb.UpdateLink(Name=r"C:\Users\XYZ\Desktop\Test\XYZ_201606.csv")
except Exception as e:
print(e)
finally:
wb.Close(True)
wb = None
return True
xl_app.Quit()
xl = None
Whenever I run this, I get the following error
(-2147352567,'Exception occured.',(0,'Microsoft Excel','UpdateLink method of
Workbook class failed','xlmain11.chm',0,-2146827284),None)
Can Somebody tell me what is going wrong here. Also, incase I have multiple links, how do I tell which link needs to be changed to what? Can I pass a dictionary of directories of updated datasets
The code and the approach has been taken from this answer on Stack Overflow
Update Links in for Excel Spreadsheet Using Python
If you review the Microsoft Documentation, it seems that the UpdateLink method can be called without any parameters. Therefore this program should work:
import win32com.client as win32
xl_app = win32.gencache.EnsureDispatch("Excel.Application")
xl_app.Visible = True
xl_app.DisplayAlerts = False
wb = xl_app.workbooks.open(r"C:\Users\XYZ\Desktop\Test\Summary.xlsx")
wb.UpdateLink()
wb.Save()
wb.Close()
xl_app.Quit()
I'm not sure if my solution solves your issue, but I had the same problem and I used LinkSources() and ChangeLink() instead
newSource = r"C:\Users\XYZ\Desktop\Test\XYZ_201606.csv"
oldSource = wb.LinkSources()
wb.ChangeLink(Name = oldSource[0], NewName = newSource, Type = 1)
Hope it helps!
Is it possible to define a route in bottle which would return a file?
I have a mongo database which is accessed by pandas.
Pandas generates a xls file based on a request parameters.
Two steps above are clear and easy to implement.
The third step is the one I have a problem with.
Define a bottle route which would return a file to download by user.
I don't want to use static previously generated files.
Thanks in advance.
I'm not familiar with Pandas but you need to get binary contents of a xls file to send to a user via a Bottle route. Modified example from here for Python 3:
from io import BytesIO
from bottle import route, response
from pandas import ExcelWriter
#route('/get-xlsx')
def get_xlsx():
output = BytesIO()
writer = ExcelWriter(output, engine='xlsxwriter')
# Do something with your Pandas data
# ...
pandas_dataframe.to_excel(writer, sheet_name='Sheet1')
writer.save()
response.contet_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
response.add_header('Content-Disposition', 'attachment; filename="report.xlsx"')
return output.getvalue()
When a user click a link that corresponds to this route, a file download dialog for "report.xlxs" will open in their browser.
views.py
def export_to_excel(request):
lists = MyModel.objects.all()
# your excel html format
template_name = "sample_excel_format.html"
response = render_to_response(template_name, {'lists': lists})
# this is the output file
filename = "model.csv"
response['Content-Disposition'] = 'attachment; filename='+filename
response['Content-Type'] = 'application/vnd.ms-excel; charset=utf-16'
return response
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('app_name.views',
url(r'^export/$', 'export_to_excel', name='export_to_excel'),
)
Last, in your page create a button or link that will point in exporting.
page.html
Export
Nothing getting file option for download and not giving any error but i can see all result in log its working fine.
I think that the solution to export excel files is :
if 'excel' in request.POST:
response = HttpResponse(content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=Report.xlsx'
xlsx_data = WriteToExcel(weather_period, town)
response.write(xlsx_data)
return response
In this example the library used for exporting is xlsxWriter.
Here is a very complete and practical solution for this, and many others: http://assist-software.net/blog/how-export-excel-files-python-django-application .
In addition to the options shown in the other answers you can also use XlsxWriter to create Excel files.
See this example.
It seems that you are trying to generate an excel workbook with HTML content. I don't know if Excel (or LibreOffice) is able to open such file but I think it is not the right approach.
You should fist generate a excel file : you can use csv, xlwt for xls and openpyxl for xlsx
The content of the file can be passed to the HttpResponse
for example, if you work with xlwt:
import xlwt
wb = xlwt.Workbook()
#use xlwt to fill the workbook
#
#ws = wb.add_sheet("sheet")
#ws.write(0, 0, "something")
response = HttpResponse(mimetype='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=the-file.xls'
wb.save(response)
return response
You can also look at
django-excel-response which does all the work for you. (I think it doesn't support xlsx format)
django-excel-export
I hope it helps
This seems to be based on the practice of tricking excel into opening an HTML table by changing the file name and MIME type. In order to make this work, the HTML file has to assemble an HTML table, and this is likely to trigger a warning that the real content of the file is different from the declared content.
IMHO it is a crude hack and should be avoided. Instead you can create a real excel file using the xlwt module, or you can create a real CSV file using the csv module.
[update]
After looking the blog post you refered, I see it is recommending another bad practice: using anything but the csv module to produce CSV files is dangerous because if the data contains the delimiter character, quotes or line breaks, you may end up with a bad CSV.
The csv module will take care of all corner cases and produce a proper formatted output.
I've seen people use a Django template naming the file "something.xls" and using HTML tables instead of the CSV format, but this has some corner cases as well.
Export Data to XLS File
Use it if you really need to export to a .xls file. You will be able to add formating as bold font, font size, define column size, etc.
First of all, install the xlwt module. The easiest way is to use pip.
pip install xlwt
views.py
import xlwt
from django.http import HttpResponse
from django.contrib.auth.models import User
def export_users_xls(request):
response = HttpResponse(content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename="users.xls"'
wb = xlwt.Workbook(encoding='utf-8')
ws = wb.add_sheet('Users')
# Sheet header, first row
row_num = 0
font_style = xlwt.XFStyle()
font_style.font.bold = True
columns = ['Username', 'First name', 'Last name', 'Email address', ]
for col_num in range(len(columns)):
ws.write(row_num, col_num, columns[col_num], font_style)
# Sheet body, remaining rows
font_style = xlwt.XFStyle()
rows = User.objects.all().values_list('username', 'first_name', 'last_name', 'email')
for row in rows:
row_num += 1
for col_num in range(len(row)):
ws.write(row_num, col_num, row[col_num], font_style)
wb.save(response)
return response
urls.py
import views
urlpatterns = [
...
url(r'^export/xls/$', views.export_users_xls, name='export_users_xls'),
]
template.html
Export all users
Learn more about the xlwt module reading its official documentation. https://simpleisbetterthancomplex.com/tutorial/2016/07/29/how-to-export-to-excel.html
I was using stackoverflow for a while now and it helped me very often. Now I have a problem I couldn't solve myself or through searching.
I'm trying to output my excel file generated by openpyxl in browser as I was doing it with phpexcel. The method appears to be the same, but I only get broken file. My code looks like this:
from openpyxl.workbook import Workbook
from openpyxl.writer.excel import ExcelWriter
from openpyxl.writer.excel import save_virtual_workbook
from openpyxl.cell import get_column_letter
from StringIO import StringIO
print 'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
print 'Content-Disposition: attachment;filename="results.xlsx"'
print 'Cache-Control: max-age=0\n'
output = StringIO()
wb = Workbook()
ws = wb.worksheets[0]
ws.cell('A1').value = 3.14
wb.save(output)
print output.getvalue()
#print save_virtual_workbook(wb)
I use the version 1.5.8 and python 2.7.
None of the approaches works. When I just use it from desktop and not browser it works flawlessly.
I would be very thankful for help.
P.S. please don't tell me that using other language or program would be easier. I need to solve this with python.
this is work for me. I use python 2.7 and latest openpyxl and send_file from flask
... code ...
import StringIO
from openpyxl import Workbook
wb = Workbook()
ws = wb.active # worksheet
ws.title = "Excel Using Openpyxl"
c = ws.cell(row=5, column=5)
c.value = "Hi on 5,5"
out = StringIO.StringIO()
wb.save(out)
out.seek(0)
return send_file(out, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
attachment_filename='xxl.xlsx', as_attachment=True)
output = HttpResponse(mimetype='application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
file_name = "Test.xlsx"
output['Content-Disposition'] = 'attachment; filename='+ file_name
wb = Workbook()
ws = wb.worksheets[0]
ws.cell('A1').value = 3.14
wb.save(output)
return output
I used this tips to download my files with openpyxl. Hope that will help
Writing the xlsx output to disk and then serving it up via Apache worked perfectly, but putting it out directly caused errors in Excel and other issues.
I added a couple of extra steps and made one minor change to your code:
buffer=output.getvalue()
In the HTTP headers:
print "Content-Length: " + str(len(buffer))
And used write() instead of print() to push the buffer into the standard output stream:
stdout.write(buffer)
Your scripts works for me as you expect without alterations.
I can only assume you have a problem with your cgi script setup.
Make sure you have the directory where the script lives actually gets served by the web server. On apache you can achieve this with:
ScriptAlias /cgi-bin/ /home/WWW/localhost/cgi-bin/
Make sure the script is excutable by setting the script permissions. For commandline operation (python scriptname) that was not necessary, for your webbrowser that is. And make sure the owner of the webserver can excute the scripts, as the webserver probably does not run as you.
Because Excel uses a binary format you should be using BytesIO to buffer.
from io import BytesIO
But what error are you getting if you use save_virtual_workbook() which does this for you?
I have same problem.
Solution is to switch stdout to bin mode:
import msvcrt
print 'Content-Type:application/octet-stream; name="{}"'.format(os.path.basename(xls_file))
print 'Content-Disposition:attachment; filename="{}"'.format(os.path.basename(xls_file))
print "Content-Length: " + str(os.path.getsize(xls_file))
print 'Cache-Control: max-age=0\r\n'
msvcrt.setmode (1, os.O_BINARY) # stdout = 1
sys.stdout.flush()
with open(xls_file, 'rb') as fobj:
copyfileobj(fobj, sys.stdout)
If you want to build an HTML table that looks like your spreadsheet, you probably want to work with CSV. Either do this, instead of Excel, OR convert your Excel to CSV after you build it.
In any case, once you have the data in CSV format, then it's simply a matter of using python to build the HTML page and looping through the CSV data, while inserting your <table>, <tr>, and <td> tags, as appropriate.