How to export excel file in django - python

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

Related

Django / Pandas - Create Excel file and serve as download

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.

Cannot open excel file generated by django

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

CSV Download of User Info Django

I am trying to download some user data into a csv file. I am able to generate the User fields just fine but when I try to access the onetoone relation field I am running into issues!
Tried numerous different way to get here. Just can't seem to figure out how to get the correct related data.
def export_to_csv (modeladmin, request, queryset):
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
from wsgiref.util import FileWrapper
cols = ['username','email','first_name','last_name','my_profile.dealer_num']
# get qs values
data = list( queryset.values_list(*cols) )
if not data:
messages.error(request, 'No data to export')
return HttpResponseRedirect( request.get_full_path() )
# create empty csv
csv_file = StringIO()
csv_writer = csv.writer(csv_file, quoting = csv.QUOTE_ALL)
# add headers
csv_writer.writerow( cols )
# add qs values
for row in data:
csv_writer.writerow( [s.encode('utf-8') for s in row] )
csv_file.flush()
csv_file.seek(0)
response = HttpResponse(FileWrapper( csv_file ), content_type='text/csv')
response['Content-Disposition'] = "attachment; filename=user-csv-export.csv"
return response
export_to_csv.short_description = "Export to CSV"
Models.py
class MyProfile(UserenaBaseProfile):
user = models.OneToOneField(User,
unique=True,
verbose_name=_('user'),
related_name='my_profile')
dealer_num = models.CharField(blank=True,
max_length=15,
verbose_name="Dealer Number")
Should return everything including a 5 digit dealer number in a csv
You are not accessing the field correctly, you need to use __ as in a query.
Change cols to:
cols = ['username','email','first_name','last_name','my_profile__dealer_num']

how to show username instead of user id using xlwt

Am exporting data to excel using xlwt but the problem that am getting user id in the row user instead of username, how to fix this,, here is the view
def export_buy_and_sell_report_csv(request):
today_date = date.today()
response = HttpResponse(content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename="BuyAndSellReports_' + str(today_date) + '.xls"'
wb = xlwt.Workbook(encoding='utf-8')
ws = wb.add_sheet('BuyAndSells')
# Sheet header, first row
row_num = 0
font_style = xlwt.XFStyle()
font_style.font.bold = True
columns = ['المستخدم', ' القيمة', 'البيان', 'الفئة', 'نوع الحركة', 'التاريخ']
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 = models.BuyAndSellReport.objects.all().values_list('user', 'amount', 'text', 'move_category', 'move_type',
'date')
rows = [[x.strftime("%Y-%m-%d %H:%M") if isinstance(x, datetime.datetime) else x for x in row] for row in
rows]
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
You probably want to access a specific property of user instead of using a foreign key in values_list.
Try constructing your query like this:
rows = models.BuyAndSellReport.objects.all().values_list('user__username', 'amount', 'text', 'move_category', 'move_type',
'date')

Want to prompt browser to save csv

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"'

Categories

Resources