How to export data in python with excel format? - python

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

Related

How do I download an xlsm file and read every sheet in python?

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

Import xlsx files in Odoo via Python script

The code below is a function which is execute when i press import products button in Odoo. This script imports products in Odoo from a csv file. The csv file can be uploaded first and then i click the import button.
What i can't do is that when i upload xlsx file and click import i get warning that the file is not valid.
Can someone help me how to enable to import also from xlsx file?
#api.one
def action_import(self):
ctx = self._context
data = base64.b64decode(self.data)
file_input = cStringIO.StringIO(data)
file_input.seek(0)
row = []
result = {}
if self.delimeter:
delimeter = str(self.delimeter)
else:
delimeter = ','
fieldnames = ['supplier_default_code', 'name', 'product_brand', 'supplier', 'standard_price', 'list_price',
'internal_category', 'spare_part', 'service_part', 'default_code', 'supplierinfo_product_name',
'rrp_price', 'min_qty', 'weight', 'net_weight', 'volume', 'height', 'width', 'depth', 'delay',
'warranty_type', 'warranty', 'sale_delay', 'description', 'description_sale',
'description_delivery', 'ean']
reader = csv.DictReader(file_input, delimiter=delimeter, fieldnames=fieldnames)
try:
row.extend(reader)
except Exception:
raise exceptions.Warning(_("Not a valid file!"))
keys = row[0]
self.create_products_from_array(row)
From your description it looks like you're expecting csv.DictReader to cope with an .xlsx file. But that is something completely different from a .csv file. The fact that Excel can open them both doesn't mean they are interchangeable, or somehow the same.
You could try using the module xlrd. But it will be a completely different implementation; the module won't provide a drop-in replacement for csv.DictReader.
The only other alternative is to preprocess the .xlsx file and transform it into the .csv that your code expects. You could use xlrd for this, or you could write a VBA macro in Excel to do it; in fact there may be a dozen ways to do it.
you can try to implement this code, Source XLS to Dict Reader using xlrd
try
import xlrd
def XLSDictReader(f, sheet_index=0):
data = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
book = xlrd.open_workbook(file_contents=data)
sheet = book.sheet_by_index(sheet_index)
def item(i, j):
return (sheet.cell_value(0,j), sheet.cell_value(i,j))
return ( dict(item(i,j) for j in range(sheet.ncols)) \
for i in range(1, sheet.nrows) )
except ImportError:
XLSDictReader = None

Django Pandas to http response (download file)

Python: 2.7.11
Django: 1.9
Pandas: 0.17.1
How should I go about creating a potentially large xlsx file download? I'm creating a xlsx file with pandas from a list of dictionaries and now need to give the user possibility to download it. The list is in a variable and is not allowed to be saved locally (on server).
Example:
df = pandas.DataFrame(self.csvdict)
writer = pandas.ExcelWriter('pandas_simple.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
This example would just create the file and save it where the executing script is located. What I need is to create it to a http response so that the user would get a download prompt.
I have found a few posts about doing this for a xlsxwriter but non for pandas. I also think that I should be using 'StreamingHttpResponse' for this and not a 'HttpResponse'.
I will elaborate on what #jmcnamara wrote. This if for the latest versions of Excel, Pandas and Django. The import statements would be at the top of your views.py and the remaining code could be in a view:
import pandas as pd
from django.http import HttpResponse
try:
from io import BytesIO as IO # for modern python
except ImportError:
from io import StringIO as IO # for legacy python
# this is my output data a list of lists
output = some_function()
df_output = pd.DataFrame(output)
# my "Excel" file, which is an in-memory output file (buffer)
# for the new workbook
excel_file = IO()
xlwriter = pd.ExcelWriter(excel_file, engine='xlsxwriter')
df_output.to_excel(xlwriter, 'sheetname')
xlwriter.save()
xlwriter.close()
# important step, rewind the buffer or when it is read() you'll get nothing
# but an error message when you try to open your zero length file in Excel
excel_file.seek(0)
# set the mime type so that the browser knows what to do with the file
response = HttpResponse(excel_file.read(), content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
# set the file name in the Content-Disposition header
response['Content-Disposition'] = 'attachment; filename=myfile.xlsx'
return response
Jmcnamara is pointing you in the rigth direction. Translated to your question you are looking for the following code:
sio = StringIO()
PandasDataFrame = pandas.DataFrame(self.csvdict)
PandasWriter = pandas.ExcelWriter(sio, engine='xlsxwriter')
PandasDataFrame.to_excel(PandasWriter, sheet_name=sheetname)
PandasWriter.save()
sio.seek(0)
workbook = sio.getvalue()
response = StreamingHttpResponse(workbook, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
Notice the fact that you are saving the data to the StringIO variable and not to a file location. This way you prevent the file being saved before you generate the response.
Maybe a bit off-topic, but it's worth pointing out that the to_csv method is generally faster than to_excel, since excel contains format information of the sheets. If you only have data and not formatting information, consider to_csv. Microsoft Excel can view and edit csv files with no problem.
One gain by using to_csv is that to_csv function can take any file-like object as the first argument, not only a filename string. Since Django response object is file-like, to_csv function can directly write to it. Some codes in your view function will look like:
df = <your dataframe to be downloaded>
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=<default filename you wanted to give to the downloaded file>'
df.to_csv(response, index=False)
return response
Reference:
https://gist.github.com/jonperron/733c3ead188f72f0a8a6f39e3d89295d
https://docs.djangoproject.com/en/2.1/howto/outputting-csv/
With Pandas 0.17+ you can use a StringIO/BytesIO object as a filehandle to pd.ExcelWriter. For example:
import pandas as pd
import StringIO
output = StringIO.StringIO()
# Use the StringIO object as the filehandle.
writer = pd.ExcelWriter(output, engine='xlsxwriter')
# Write the data frame to the StringIO object.
pd.DataFrame().to_excel(writer, sheet_name='Sheet1')
writer.save()
xlsx_data = output.getvalue()
print len(xlsx_data)
After that follow the XlsxWriter Python 2/3 HTTP examples.
For older versions of Pandas you can use this workaround.
Just wanted to share a class-based view approach to this, using elements from the answers above. Just override the get method of a Django View. My model has a JSON field which contains the results of dumping a dataframe to JSON with the to_json method.
Python version is 3.6 with Django 1.11.
# models.py
from django.db import models
from django.contrib.postgres.fields import JSONField
class myModel(models.Model):
json_field = JSONField(verbose_name="JSON data")
# views.py
import pandas as pd
from io import BytesIO as IO
from django.http import HttpResponse
from django.views import View
from .models import myModel
class ExcelFileDownloadView(View):
"""
Allows the user to download records in an Excel file
"""
def get(self, request, *args, **kwargs):
obj = myModel.objects.get(pk=self.kwargs['pk'])
excel_file = IO()
xlwriter = pd.ExcelWriter(excel_file, engine='xlsxwriter')
pd.read_json(obj.json_field).to_excel(xlwriter, "Summary")
xlwriter.save()
xlwriter.close()
excel_file.seek(0)
response = HttpResponse(excel_file.read(),
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename="excel_file.xlsx"'
return response
# urls.py
from django.conf.urls import url
from .views import ExcelFileDownloadView
urlpatterns = [
url(r'^mymodel/(?P<pk>\d+)/download/$', ExcelFileDownloadView.as_view(), name="excel-download"),]
You're mixing two requirements that should be separate:
Creating a .xlsx file using python or pandas--it looks like you're good on this part.
Serving a downloadable file (django); see this post or maybe this one

Parsing xlsx sheet from HTTP response using openpyxl library

I am writing a test case for testing Excel sheet parsing.
I tried to parse the response.content into list of objects using openpyxl.
I have extracted the filename from response header and converted into File like object. load_workbook() is not accepting the filename.
def test_export_timesheet(self):
change_url = '/admin/core/timesheet/'
#response contains the generated file using openpyxl
response = self.client.post(change_url, {'action': 'export_xlsx', '_selected_action': [x.id for x in timesheets]})
content = response._headers.get('content-disposition')[1]
start = content.find('=') + 1
end = content.find('.xlsx')
content_path = (content[start:end]+'.xlsx')
#Passing file like object
wb = load_workbook(BytesIO(filename="'"+content_path+"'"))
ws = wb.get_sheet_by_name(name="'" + content[start:end] + "'")
for row in ws.iter_rows():
for cell in row:
print cell.value
Basically I am trying to validate the contents of the file in my testcase.
Is there a way to do this?
# response contains the generated file using openpyxl
response = self.client.post(change_url, ・・・・・
When you get the response above, "response.content" is bytes-type, so you can load it into the buffer with BytesIO. Continuing from above, write:
from io import BytesIO
file_like_object = BytesIO(response.content)
(from openpyxl import load_workbook) # if this line is needed...
wb = load_workbook(file_like_object)
Now you can use this "wb" for general openpyxl operations

Create and return spreadsheet with Django

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.

Categories