Python-Django utf-8 csv.writer - python

im using python csv library for exporting my models into a csv file in django.
codes are like this :
import csv
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
writer = csv.writer(response)
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
return response
My problem :
in my database i have some persian characters that just works with utf-8 encoding format , so when i open generated csv file in excel the persian characters not shown correctly.

i try encode('UTF-8') Solution in some cases, but the result in microsoft excel is not readable , it shows b'\xd8\xb1\xdb\x8c\xd8'.
However i find the correct way for showing CSV in excel readable.
import csv
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
response.write(u'\ufeff'.encode('utf8'))
writer = csv.writer(response)
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
return response
Just add response.write(u'\ufeff'.encode('utf8')) into the code

just add this new line code :
response.write(codecs.BOM_UTF8)
after this line :
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'

use this i have arabic character and worked fine for me
def university_csv(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="university_list.csv"'
writer = csv.writer(response)
university_obj = Universities.objects.using('cms').all()
writer.writerow(['id', 'NAME', 'ABBREVIATION', 'ADDRESS'])
for item in university_obj:
if item.address:
if item.abbreviation:
writer.writerow([item.id, item.name.encode('UTF-8'), item.abbreviation.encode('UTF-8'),
item.address.encode('UTF-8')])
else:
writer.writerow([item.id, item.name.encode('UTF-8'), item.abbreviation, item.address.encode('UTF-8')])
else:
if item.abbreviation:
writer.writerow([item.id, item.name.encode('UTF-8'), item.abbreviation.encode('UTF-8')])
else:
writer.writerow([item.id, item.name.encode('UTF-8')])
return response

First of all add a:
# coding: utf-8
At the top of your .py file. Second, it's not an Django issue, it's rather the MS Excel issue. I had a similar problem last week and found that in excel when you choose the encoding you just need to set the language code (or something like that) to UTF-8 family rather the Persian.

Related

Django how to create a tmp excel file and return it to the browser within the response

I have a process to build a tmp file and then return it to the browser in csv. Now i want to do the same but return a excel file.
So what i have for the csv is a view in django that does:
def export_wallet_view(request):
tmp = tempfile.NamedTemporaryFile(delete=False)
with open(tmp.name, 'w', encoding="utf-8-sig") as fi:
csv_headers = [
'Id',
'Name'
]
fi.write(';'.join(csv_headers))
fi.write('\n')
//here also i save the rows into the file
response = FileResponse(open(tmp.name, 'rb'))
response['Content-Disposition'] = 'attachment; filename="wallet.csv"'
return response
So to convert it to excel i try to do something like this using pandas:
df = pd.read_csv(tmp.name)
df.to_excel('pandas_to_excel.xlsx', sheet_name='new_sheet_name')
The problem is that this creates the excel in the server, and i would like to do something like:
df = pd.read_csv(tmp.name)
df.to_excel('pandas_to_excel.xlsx', sheet_name='new_sheet_name') //this being a tmp file
response = FileResponse(open(tmp.name, 'rb')) //this should be the new excel tmp file
response['Content-Disposition'] = 'attachment; filename="wallet.csv"'
return response
Thanks
I don't understand your problem.
You should use the same 'pandas_to_excel.xlsx' in both
df.to_excel('pandas_to_excel.xlsx', ...)
... open('pandas_to_excel.xlsx', 'rb')
or the same tmp.name in both
df.to_excel(tmp.name, ...)
... open(tmp.name, 'rb')
You can even use again NamedTemporaryFile() to create new temporary name.
tmp = tempfile.NamedTemporaryFile(delete=False)
df.to_excel(tmp.name, ...)
... open(tmp.name, 'rb')
But popular method is to use io.String() or io.Bytes() to create file-like object in memory - without creating file on disk.
def export_wallet_view(request):
csv_headers = ['Id', 'Name']
file_like_object = io.Bytes()
file_like_object.write(';'.join(csv_headers).encode('utf-8-sig'))
file_like_object.write('\n'.encode('utf-8-sig'))
file_like_object.write('other rows'.encode('utf-8-sig'))
file_like_object.seek(0) # move to the beginning of file
response = FileResponse(file_like_object)
response['Content-Disposition'] = 'attachment; filename="wallet.csv"'
return response
For excel it could be something like this. I use io.String() to read csv directly to pandas, and later I use io.Bytes() to create file-like object with excel data.
def export_wallet_view(request):
csv_headers = ['Id', 'Name']
text = ';'.join(csv_headers)
text += '\n'
text += 'other rows'
df = pd.read_csv(io.String(text))
file_like_object = io.Bytes()
df.to_excel(file_like_object)
file_like_object.seek(0) # move to the beginning of file
response = FileResponse(file_like_object)
response['Content-Disposition'] = 'attachment; filename="pandas_to_excel.xlsx"'
return response

Better way to file response with DRF?

I have this action:
#action(methods=['get'], detail=True)
def download_csv(self, request, pk, *args, **kwargs):
project = self.get_object()
data = show_stages_tasks(request, pk)
file_name = f"{project.name}.csv"
export_to_csv(data, file_name)
file_handle = open(file_name, "r")
response = FileResponse(file_handle.read(), content_type='application/csv')
response['Content-Disposition'] = f'attachment; filename="{file_handle.name}"'
file_handle.close()
os.remove(file_name)
return response
and export_to_csv is:
def export_to_csv(data, filename="project"):
content = JSONRenderer().render(data)
stream = io.BytesIO(content)
content_parsed = JSONParser().parse(stream)
tasks = content_parsed[0]["related_tasks"]
keys = tasks[0].keys()
with open(filename, 'w') as output_file:
dict_writer = csv.DictWriter(output_file, fieldnames=keys)
dict_writer.writeheader()
for task in tasks:
task['children'] = []
task['task_folders'] = []
dict_writer.writerow(task)
And show_stages_tasks returns a serialized data with DRF serializer, with 3 nested serializers (too big and I think unnecessary to post it here).
As you see here - I parse serializer data, create a CSV file, save it, next open it, pass in the Response and delete file. The question is can I somehow pass the content of the file, without actually creating CSV file and next deleting it?
From the Django's official doc, you could find a similar example.
In that example, they are using django.http.HttpResponse class, it can be also used in your case
import csv
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
writer = csv.writer(response)
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
return response

How to set secured path settings using Python

I need one help. I am uploading file into folder and for that I have set constant in settings.py file using Python. I am explaining my code below.
settings.py:
FILE_PATH = os.getcwd()+'/upload/'
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
Here I need the secured file path to upload the downloaded file into folder using Python and Django.
Are you writing to the file row by row? I would make a list or dataframe first & then write that to the csv.
import pandas as pd
#make your dataframe by adding your rows to a list
df = pd.DataFrame(list)
df.to_csv(filepath)

How download file and save it inside the upload folder using Django and Python

I am trying to write the content in CSV file and Here I need to download that file and save that same file into upload folder. My code is below.
if request.method == 'POST':
param = request.POST.get('param')
report = Reactor.objects.all()
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename='+uuid.uuid4()+'.csv'
writer = csv.writer(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'
writer.writerow([rec.rname, status, rec.date])
#return response
u = urllib.URLopener()
f = u.open(param)
open("down.txt","w").write(f.read())
pers = User.objects.get(pk=request.session['id'])
root = []
user_name = pers.uname
count = 1
root.append(
{'username': user_name,
'count': count
})
return render(request, 'plant/home.html',
{'user': root, 'count': 1})
Here I am setting the database values inside one CSV file and that file is named as unique id. Here I need to save that file inside Upload folder and that folder path will set inside settings.py file and also same file will be downloaded as well.
You should try to generate your CSV into a buffer an then use it to save it to the file system and use it again to return the CSV as the respone. Something like this
import csv
import os
import shutil
from io import StringIO
from django.http import HttpResponse
from django.conf import settings
def my_view(request):
csvbuffer = StringIO
writer = csv.writer(csvbuffer)
# Write data from the DB here into the CSV buffer
# Write the file to the file system
path = os.path.join(settings.FILE_PATH, "%s.csv" % uuid.uuid4())
with(path, 'w') as fd:
csvbuffer.seek(0)
shutil.copyfileobj(csvbuffer, fd)
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
csvbuffer.seek(0)
response.write(csvbuffer)
return response
I am quite sure this not the most optimized way to do it, but at least it should works.

How to implement csvwriter in python on Google App Engine

I have an app that works to write a csv as a response to a specific URL call. But, I don't know how to escape characters.
Right now, my code looks like this
import csv
class ReturnCSV(BaseHandler):
def get(self, group_id):
self.response.headers['Content-Type'] = 'text/csv'
self.response.headers['Content-Disposition'] = "attachment; filename=scenarios.csv"
self.write(','.join(header)) #header is a list defined elsewhere
for scenario in list_of_scenarios:
#do stuff
self.write('\r\n' + ','.join(output)))
This gets me the expected output, except that it doesn't escape special characters. I figured I need to implement csv.writer with QUOTE_ALL, but when trying that, I get an IOError(errno.EROFS, 'Read-only file system', filename)
self.response.headers['Content-Type'] = 'text/csv'
self.response.headers['Content-Disposition'] = "attachment; filename=scenarios.csv"
with open('scenarios.csv', 'w') as output:
row = ','.join(header)
wr = csv.writer(output, quoting=csv.QUOTE_ALL)
wr.writerow(row)
for scenario in list_of_scenarios:
#do stuff
wr.writerow(output)
So, got it to work if I don't try to open the file and then I take out all the ','.join that I was doing to manually create CSV.
output = StringIO.StringIO()
row = header #header created elsewhere
wr = csv.writer(output, quoting=csv.QUOTE_MINIMAL)
wr.writerow(row)
for scenario in list_of_scenarios:
# do stuff
wr.writerow(datarow)
self.response.headers['Content-Type'] = 'text/csv'
self.response.headers['Content-Disposition'] = "attachment; filename=scenarios.csv"
self.write(output.getvalue())

Categories