Im trying to take user input from a form and then using that data to create a document using python docx module. But the downloaded file is not opening in MS word. It says the file is corrupt. Can someone help me with this?
def resume_form(request):
form = forms.resume()
if request.method == 'POST':
form = forms.resume(request.POST)
if form.is_valid():
document = Document()
document.add_heading(str(form.cleaned_data['full_name']),0)
document.add_heading('Summary', 1)
document.add_paragraph(str(form.cleaned_data['summary']))
f = io.BytesIO()
document.save(f)
length = f.tell()
f.seek(0)
response = HttpResponse(document, content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
response['Content-Disposition'] = 'attachment; filename=download.docx'
response['Content-Length'] = length
#document.save(response)
return response
return render(request, 'sample_app/index.html', {'form' : form})
I think you have the answer already in your code: you can (and should) write your document directly to the response, rather than use an intermediary BytesIO.
...
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
response['Content-Disposition'] = 'attachment; filename = "download.docx"'
document.save(response)
return response
You must read from io in the response with getvalue(), since you're writing document to io.
response = HttpResponse(f.getvalue(), content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
Or you can write directly to response as #paleolimbot pointed out.
Related
I have converted on Excel(with 2 tabs) to HTML. Now I want to display this generated HTML on a webpage with Django code. But I am not able to get the entire data in my webpage.
Following is my Django code.
#api_view(['GET'])
def download_y9cfile1(request, file_name):
filePath = CommonUtils.get_absolute_file_path('app','static','generated','HTML', file_name)
logger.debug("File name is %s" % filePath )
try:
relevantFile = open(filePath,'rb')
response = HttpResponse((relevantFile), content_type='text/html')
response['Content-Disposition'] = 'inline; filename="%s"' %file_name
except IOError:
logger.exception("File doesn't exist")
return HttpResponse("File doesn't exist", status=500)
return response
I think the issue is that Django is not able to read the supporting CSS file for HTML.
Try passing the file contents to HttpResponse instead of the file handle:
response = HttpResponse(relevantFile.read(), content_type='text/html')
I create a link that when a user press it, it will download a pdf file from the media folder in Django to the users machine.
I tried different methods but all were wrong for me. It tells me that the file can not be found, or the code is running but the file is corrupted.
My Html link:
<td> Download</td>
My url pattern links into a view:
url(r'^download/$', views.DownloadPdf),
My FileField is like this:
upload_pdf = models.FileField()
Following snippet code is the view that downloads a corrupted pdf:
def DownloadPdf(request):
filename = '/home/USER/PycharmProjects/MyProject/media/Invoice_Template.pdf'
response = HttpResponse(content_type='application/pdf')
fileformat = "pdf"
response['Content-Disposition'] = 'attachment;
filename=thisismypdf'.format(fileformat)
return response
So, what I have to do to make it working ?
with open(os.path.join(settings.MEDIA_ROOT, 'Invoice_Template.pdf'), 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/pdf")
response['Content-Disposition'] = 'attachment; filename=invoice.pdf'
return response
#Sergey Gornostaev 's code just work perfect, but i post below my code because it is a aproach in a differect way.
I correct a little bit my code:
def DownloadPdf(request):
path_to_file = '/home/USER/PycharmProjects/MyProject/media /Invoice_Template.pdf'
f = open(path_to_file, 'r')
myfile = File(f)
response = HttpResponse(myfile, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=filename'
return response
But only in pdf file ( works with txt files ) gives me that error:
'utf-8' codec can't decode byte 0xe2 in position 10
I'm trying to let the user download an xml file that i have generated.
This is my code:
tree.write('output.xml', encoding="utf-16")
# Pathout is the path to the output.xml
xmlFile = open(pathout, 'r')
myfile = FileWrapper(xmlFile.read())
response = HttpResponse(myfile, content_type='application/xml')
response['Content-Disposition'] = 'attachment; filename='+filename
return response
When I try to create my response I get this exception:
'\\'str\\' object has no attribute \\'read\\''
Can't figure out what I'm doing wrong. Any ideas?
Edit:
When I use this code I get no errors but instead the downloaded file is empty
tree.write('output.xml', encoding="utf-16")
xmlFile = open(pathout, 'r')
myfile = FileWrapper(xmlFile)
response = HttpResponse(myfile, content_type='application/xml')
response['Content-Disposition'] = 'attachment; filename='+filename
return response
You are calling xmlFile.read() - which yields a string - and passing the result to FileWrapper() which expects a readable file-like object. You should either just pass xmlFile to FileWrapper, or not use FileWrapper at all and pass the result of xmlFile.read() as your HttpResponse body.
Note that if you are creating the xml dynamically (which seems to be the case according to your snippet's first line), writing it to disk only to read it back a couple lines later is both a waste of time and resources and a potential cause of race conditions. You perhaps want to have a look at https://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.tostring
You're reading the file and passing the resulting string to FileWrapper, instead of passing the actual file object.
myfile = FileWrapper(xmlFile)
Alternatively from the other answers, I would recommend to completely go around the problem by utilizing the Django template system:
from django.http import HttpResponse
from django.template import Context, loader
def my_view(request):
# View code here...
t = loader.get_template('myapp/myfile.xml')
c = Context({'foo': 'bar'})
response = HttpResponse(t.render(c), content_type="application/xml")
response['Content-Disposition'] = 'attachment; filename=...'
return response
In this way create a myfile.xml template which is used to render the proper xml response without having to deal with writing any files to the filesystem. This is cleaner and faster, given that there is no other need to indeed create the xml and store it permanently.
I'm trying create and serve excel files using Django. I have a jar file which gets parameters and produces an excel file according to parameters and it works with no problem. But when i'm trying to get the produced file and serve it to the user for download the file comes out broken. It has 0kb size. This is the code piece I'm using for excel generation and serving.
def generateExcel(request,id):
if os.path.exists('./%s_Report.xlsx' % id):
excel = open("%s_Report.xlsx" % id, "r")
output = StringIO.StringIO(excel.read())
out_content = output.getvalue()
output.close()
response = HttpResponse(out_content,content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
args = ['ServerExcel.jar', id]
result = jarWrapper(*args) # this creates the excel file with no problem
if result:
excel = open("%s_Report.xlsx" % id, "r")
output = StringIO.StringIO(excel.read())
out_content = output.getvalue()
output.close()
response = HttpResponse(out_content,content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
return HttpResponse(json.dumps({"no":"excel","no one": "cries"}))
I have searched for possible solutions and tried to use File Wrapper also but the result did not changed. I assume i have problem with reading the xlsx file into StringIO object. But dont have any idea about how to fix it
Why on earth are you passing your file's content to a StringIO just to assign StringIO.get_value() to a local variable ? What's wrong with assigning file.read() to your variable directly ?
def generateExcel(request,id):
path = './%s_Report.xlsx' % id # this should live elsewhere, definitely
if os.path.exists(path):
with open(path, "r") as excel:
data = excel.read()
response = HttpResponse(data,content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
# quite some duplication to fix down there
Now you may want to check weither you actually had any content in your file - the fact that the file exists doesn't mean it has anything in it. Remember that you're in a concurrent context, you can have one thread or process trying to read the file while another (=>another request) is trying to write it.
In addition to what Bruno says, you probably need to open the file in binary mode:
excel = open("%s_Report.xlsx" % id, "rb")
You can use this library to create excel sheets on the fly.
http://xlsxwriter.readthedocs.io/
For more information see this page. Thanks to #alexcxe
XlsxWriter object save as http response to create download in Django
my answer is:
def generateExcel(request,id):
if os.path.exists('./%s_Report.xlsx' % id):
with open('./%s_Report.xlsx' % id, "rb") as file:
response = HttpResponse(file.read(),content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s_Report.xlsx' % id
return response
else:
# quite some duplication to fix down there
why using "rb"? because HttpResponse class init parameters is (self, content=b'', *args, **kwargs), so we should using "rb" and using .read() to get the bytes.
When I open my text file attachment that is generated using the below code, the HTTP response always seems to strip out the CR from each line, the users of this file will be using Notepad so I need CR/LF on each line.
the_file = tempfile.TemporaryFile(mode='w+b')
<procedure call to generate lines of text in "the_file">
the_file.seek(0)
filestring = the_file.read()
response = HttpResponse(filestring,
mimetype="text/plain")
response['Content-Length'] = the_file.tell()
response['Content-Disposition'] = 'attachment; filename="4cos_example.txt"'
return response
If I use this method, I get CR/LF in my files but I'd like to avoid having to write the file to disk at all, so it doesn't seem to be a good solution:
the_file = open('myfile.txt','w+')
<procedure call to generate lines of text in "the_file">
the_file.close
the_file = open('myfile.txt','rb')
filestring = the_file.read()
response = HttpResponse(filestring,
mimetype="text/plain")
response['Content-Length'] = the_file.tell()
response['Content-Disposition'] = 'attachment; filename="4cos_example.txt"'
return response
I feel like the solution should be obvious. but I can't close a tempfile and re-open it in binary mode (preserving the CR/LR). Heck I'm not even sure i'm in the right ballpark regarding how to correctly do this :) None the less, I'd like to pass this data as an attachment to the user after the configuration is assembled and have it display correctly in notepad. Is tempfile the wrong solution here or is there a mechanic of tempfile that will solve this issue for me without having to use file IO on disk.
Instead of using TemporaryFile, just use HttpResponse:
response = HttpResponse('', content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename="4cos_example.txt"'
response.write('first line\r\n')
response.write('second line\r\n')
return response
FYI, if this is a very large response, you can also use StreamingHttpResponse. But only do that if required, since headers like Content-Length will not be able to be added automatically.