I am trying to create an Excel file using pandas and serving it to the user as a downloadable file via Django. I put together some different answers on the topic that I found on here and ended up with this code:
collection = [{"title": "something", "price": 34, "quantity": 23}, {..}]
output = BytesIO()
df = pd.DataFrame(collection, columns=['title', 'price', 'quantity'])
writer = pd.ExcelWriter(output, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
output.seek(0)
workbook = output.getvalue()
response = StreamingHttpResponse(workbook, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = f'attachment; filename={output_name}.xlsx'
return response
It all works well until I try to open the resulting file - I can an error saying that the file is damaged or that there is something wrong with the data-format. I suspect that it could have something to do with the data being binary? How can I resolve this issue?
SOLUTION
Turns out I had to remove some stuff so the code looks like this now and works fine:
collection = [{"title": "something", "price": 34, "quantity": 23}, {..}]
output = BytesIO()
df = pd.DataFrame(collection, columns=['title', 'price', 'quantity'])
writer = pd.ExcelWriter(output, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
output.seek(0)
# workbook = output.getvalue()
response = StreamingHttpResponse(output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = f'attachment; filename={output_name}.xlsx'
return response
I think you might be making that a lot more complicated than it needs to be.
Below works fine for me:
import pandas as pd
from django.http import HttpResponse
df = pd.DataFrame(data)
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename="filename.xlsx"'
df.to_excel(response)
return response
SOLUTION
Turns out I had to remove some stuff so the code looks like this now and works fine:
collection = [{"title": "something", "price": 34, "quantity": 23}, {..}]
output = BytesIO()
df = pd.DataFrame(collection, columns=['title', 'price', 'quantity'])
writer = pd.ExcelWriter(output, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
output.seek(0)
# workbook = output.getvalue()
response = StreamingHttpResponse(output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = f'attachment; filename={output_name}.xlsx'
return response
Probably a datatype issue when opening in Excel, try converting the data into strings and then create excel and try.
Another thought is to create file with a sample set of records, rather than whole frame to validate if its a data issue. There might be an issue with Nan's in the dataset as well. Check if you need to ignore/convert/replace that.
Related
Say there's a dataframe from pandas like :
mediabuy cpa mediabuy cpc
cost 2020-02 0.00 371929.95 15956581.16 16328511.11
2020-04 1311.92 224747.07 26710431.81 26936490.80
total 1311.92 596677.02 42667012.97 43265001.91
I want to create an excel file in django, and I've tried with codes as below:
# return excel view
df = pd.DataFrame(data, index=index, columns=column)
# saved as excel
excel_writer = pd.ExcelWriter(path='temp.xlsx', engine='openpyxl')
df.to_excel(excel_writer)
wb = excel_writer.book
response = HttpResponse(save_virtual_workbook(wb))
response["Content-Type"] = 'application/vnd.ms-excel'
response['Content-Disposition'] = 'attachment; filename={}.xlsx'.format("data"))
return response
I'm working with python3.6.8, django2.2.4, pandas1.0.3, openpyxl3.0.3
But I always get an error saying "excel file cannot opened because the file format or file extension is not valid".
Why am I getting this error?
Thanks.
Unless there is a problem with the structure of the data in the dataframe you should be able to achieve this using:
from io import BytesIO
df = pd.DataFrame(data, index=index, columns=column)
stream_file = BytesIO()
df.to_excel(stream_file)
stream_file.seek(0)
response = HttpResponse(stream_file)
response["Content-Type"] = 'application/vnd.ms-excel'
response['Content-Disposition'] = 'attachment; filename={}.xlsx'.format("data")
return response
I need help with exporting data using a template. I installed django-import-export and added it to admin panel, now I can only export data from the admin panel. I want to know how can i export excel file using template.
This should get you started:
import StringIO
import xlsxwriter
from django.http import HttpResponse
def export_page(request):
# create our spreadsheet. I will create it in memory with a StringIO
output = StringIO.StringIO()
workbook = xlsxwriter.Workbook(output)
worksheet = workbook.add_worksheet()
worksheet.write('A1', 'Some Data')
workbook.close()
# create a response
response = HttpResponse(content_type='application/vnd.ms-excel')
# tell the browser what the file is named
response['Content-Disposition'] = 'attachment;filename="some_file_name.xlsx"'
# put the spreadsheet data into the response
response.write(output.getvalue())
# return the response
return response
I tried the same with newer version of Django and after trial and error found this worked.
import io
import xlsxwriter
def excelreport(request):
buffer = io.BytesIO()
workbook = xlsxwriter.Workbook(buffer)
worksheet = workbook.add_worksheet()
worksheet.write('A1', 'Some Data')
workbook.close()
buffer.seek(0)
return FileResponse(buffer, as_attachment=True, filename='report.xlsx')
You can alos use xlwt 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.
$ pip install xlwt
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
If you are using pandas, this is probably the easiest and most concise way:
import pandas as pd
from django.http import HttpResponse
def export_excel_file(request):
df = pd.read_excel("excel_filename.xlsx")
response = HttpResponse(content_type='application/vnd.ms-excel')
response['Content-Disposition'] = f'attachment; filename=excel_filename.xlsx'
df.to_excel(response, index=False)
return response
I need some help. I need to save the .csv file into local folder using Python but its storing the blank file. I am explaining my code below.
views.py:
report = Reactor.objects.all()
filename = str(uuid.uuid4()) + '.csv'
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename='+filename
with open(settings.FILE_PATH + filename, 'w') as csv_file:
file_writer = csv.writer(csv_file)
response_writer = csv.writer(response)
file_writer.writerow(['Name', 'Status', 'Date'])
response_writer.writerow(['Name', 'Status', 'Date'])
for rec in report:
if rec.status == 1:
status = 'Start'
if rec.status == 0:
status = 'Stop'
if rec.status == 2:
status = 'Suspend'
file_writer.writerow([rec.rname, status, rec.date])
response_writer.writerow([rec.rname, status, rec.date])
return response
settings.py:
FILE_PATH = os.getcwd()+'/upload/'
Here I am also downloading the file and I need to save that file into folder but here some blank file is storing. Please help me.
As jasonharper said you are only writing the csv data to the response and not to the file on the disk. Start by creating another writer object:
file_writer = csv.writer(open(settings.FILE_PATH + filename, 'w'))
Now each time you call writerow on writer also do this for the file_writer:
file_writer.writerow(['Name', 'Status', 'Date'])
...
file_writer.writerow([rec.rname, status, rec.date])
It is best to use the with statement to let python automatically close the file:
with open(settings.FILE_PATH + filename, 'w') as csv_file:
file_writer = csv.writer(csv_file)
response_writer = csv.writer(response)
file_writer.writerow(['Name', 'Status', 'Date'])
response_writer.writerow(['Name', 'Status', 'Date'])
for rec in report:
...
file_writer.writerow([rec.rname, status, rec.date])
response_writer.writerow([rec.rname, status, rec.date])
return response
I try to put statistics in excel spreadsheets in dynamic way, so when
excel.js
$('.js-excel').on('click', function () {
$.get(
'/ajax/stat_excel/',
{
'excel': 'loan',
'date_from': $('#date_from').val(),
'date_to': $('#date_to').val()
}
)
})
then
view.py
output = StringIO.StringIO()
workbook = xlsxwriter.Workbook(output)
if request.GET.get('excel') == 'loan':
workbook = loanChart.excel(workbook)
if request.GET.get('excel') == 'debet':
workbook = debetChart.excel(workbook)
workbook.close()
xlsx_data = output.getvalue()
response = HttpResponse(xlsx_data, mimetype='application/vnd.ms-excel')
response['Content-Type'] = 'application/vnd.ms-excel'
response['Content-Disposition'] = 'attachment; filename=report.xlsx'
return response
And I'm not sure what I'm doing wrong, because response be like
PK�������F��AS]$��w������xl/worksheets/sheet1.xml��[oɑ���W|W+#�>�dx(�{}�%j$�$
$������ʞ��8�]C�.��QU���������//�q�����ۛ:�����?|���77��y�n^<=�}�p�������������y����O���,���
Excel file generates excellent. I can see it, if I don't use StringIO
I'm not sure, what I need to use, Mimetype or Content-Type. Can't see any difference. Works exactly the same, no matter which type I write in response.
Where can be my problem?
Found answer here https://stackoverflow.com/a/4518775/4498908.
I can't use ajax for file download. But I can:
function download(path,val) {
window.location.href = path+"download.php?val="+val;
};
Want to prompt browser to save csv using pyramid.response.Response searched for clues and found here's a link Django answer but i can't use it with Pyramid wsgi my code looks like this:
from pyramid.response import Response
def get_list_names_emails(request):
session, env = request.db, request.client_env
response = Response(content_type='text/csv')
output = StringIO()
writer = csv.writer(output)
writer.writerow(['SomeName', 'SomeEmail', 'CompanyName])
csv_output = output.getvalue()
return csv_output
As a cleaner way to do that, you can register a renderer.
In your configuration set-up, add:
config.add_renderer(name='csv',
factory='mypackage.renderers.CSVRenderer')
then in mypackage/renderers.py:
class CSVRenderer(object):
def __init__(self, info):
pass
def __call__(self, value, system):
fout = StringIO.StringIO()
writer = csv.writer(fout, delimiter=';', quoting=csv.QUOTE_ALL)
writer.writerow(value['header'])
writer.writerows(value['rows'])
resp = system['request'].response
resp.content_type = 'text/csv'
resp.content_disposition = 'attachment;filename="report.csv"'
return fout.getvalue()
After that, you can decorate your view with the renderer:
#view_config(..., renderer='csv')
def myview(self):
header = ['name', 'surname', 'address']
rows = [
(
row['name'],
row['surname'],
row['address'],
)
for row in query_rows(.....)
]
return {
'header': header,
'rows': rows
}
The advantage of this approach is better testable view code (you just check for the dictionary values, no need to parse anything) and you can also add a XLS or whatever renderer to the same view:
#view_config(..., renderer='xls')
#view_config(..., renderer='csv')
def myview(self):
...
Try adding Content-Disposition:
response['Content-Disposition'] = 'attachment; filename="report.csv"'
It's better to set content type as well
response['Content-type'] = 'text/csv'
response['Content-Disposition'] = 'attachment; filename="report.csv"'