django PDF FileResponse "Failed to load PDF document." - django

I am trying to generate and output PDF from a django view. I followed the example in django documentation using ReportLab but the downloaded PDF is not opening in any PDF readers.
I use Python 3.7.0, Django==2.1.3, reportlab==3.5.12. I tried adding content_type="application/pdf" to 'FileResponse` but still having the same issue.
import io
from django.http import FileResponse
from reportlab.pdfgen import canvas
def printPDF(request):
# Create a file-like buffer to receive PDF data.
buffer = io.BytesIO()
# Create the PDF object, using the buffer as its "file."
p = canvas.Canvas(buffer)
p.drawString(100, 100, "Hello world.")
p.showPage()
p.save()
return FileResponse(buffer, as_attachment=True, filename='hello.pdf')
The generated PDF should be opening in all PDF readers. But I am getting 'Failed to load PDF document.'

buffer = BytesIO() is used instead of a file to store the pdf document. Before returning it with FileResponse you need to reset the stream position to its start:
buffer.seek(io.SEEK_SET)
Now the pdf download should work as expected.

There seems to be something fishy going on with the interaction of BytesIO and FileResponse. The following worked for me.
def printPDF(request):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=hello.pdf'
p = canvas.Canvas(response)
p.drawString(100, 100, "Hello world.")
p.showPage()
p.save()
return response

Related

Error while sending PDF through Django link

Fairly New to Django Here. I tried sending a CSV successfully using this code but I'm getting the following error sending a pdf file I generated using PDFpages from matplotlib
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xac in position
10: invalid start byte
Here's the code
def download_file(request):
# fill these variables with real values
fl_path = 'file.pdf'
filename = 'report.pdf'
fl = open(fl_path, 'r', encoding='utf-8')
mime_type, _ = mimetypes.guess_type(fl_path)
print(mime_type)
response = HttpResponse(fl, content_type=mime_type)
response['Content-Disposition'] = "attachment; filename=%s" % filename
return response
Is there a way to know which is the correct encoding I need to send my file through?
Use django's FileResponse instead of HttpResponse,
FileResponse is more ideal for send file data.
return FileResponse(fl, filename=''.format(filename ), as_attachment=True,
content_type='application/pdf')

how to prompt user to save a pdf file to his local machine in django?

I am fairly new to Django and my project requires me to prompt user to open a pdf upon clicking a link. I already have the pdf file on my local machine and dont want to recreate it using Reportlab. Is there any way to do it?
I tried
with open("/user/some/directory/somefilename.pdf") as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
return response
but it returned 404 page not found as the requested url wasn't in the URLconf of myproject.urls
What am I missing?
In general, when user click "Download", you can:
- If file is not existed:
- Generate pdf file use ReportLab as you did.
- Store generated file to a public dir.
return HttpResponseRedirect(file_url_to_public_dir)
The way that worked for me is by using FileSystemStorage
from django.core.files.storage import FileSystemStorage
from django.http import HttpResponse
fs = FileSystemStorage("/Users/location/where/file/is_saved/")
with fs.open("somefile.pdf") as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="my_pdf.pdf"'
return response
and now its prompting the user to save the file as it normally would!

django pandas dataframe download as excel file

I have a Django app that will be placed in a Docker container.
The app prepares data in Dataframe format. I would like to allow the user to download the data to his/her local drive as excel file.
I have used df.to_excel in the past, but this won't work in this case.
Please advise best way to do this.
As of pandas-0.17, you can let Django write to a BytesIO directly, like:
from django.http import HttpResponse
from io import BytesIO
def some_view(request):
with BytesIO() as b:
# Use the StringIO object as the filehandle.
writer = pd.ExcelWriter(b, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
# Set up the Http response.
filename = 'django_simple.xlsx'
response = HttpResponse(
b.getvalue(),
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
You might need to install an Excel writer module (like xlsxwriter, or openpyxl).
I think it can be even simpler and more concise these days. You can just pass the http response directly to the Excel writer. The following works for me:
from django.http import HttpResponse
import pandas as pd
# df = CREATE YOUR OWN DATAFRAME
response = HttpResponse(content_type='application/xlsx')
response['Content-Disposition'] = f'attachment; filename="FILENAME.xlsx"'
with pd.ExcelWriter(response) as writer:
df.to_excel(writer, sheet_name='SHEET NAME')
return response

How to make a pop up generated file download in Django 2?

I was working on a barcode image generate system and make pdf for printing.
Here is my view.py
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch, cm
from reportlab.platypus import Paragraph
canvas.Canvas('assets/pdf_print/'+barCode+'.pdf')
c.drawImage('1.png',0.9*cm,0,3.5*cm,1.8*cm)
c.drawImage('1.png',4.8*cm,0,3.5*cm,1.8*cm)
c.drawImage('1.png',8.9*cm,0,3.5*cm,1.8*cm)
c.drawImage('1.png',12.7*cm,0,3.5*cm,1.8*cm)
c.drawImage('1.png',16.7*cm,0,3.5*cm,1.8*cm)
c.showPage()
c.save()
I save that pdf file in this path successfully using report lab
assets/pdf_print/
After saving that file in that path, I need to generate a popup download for this file.
How could I do that in Django?
just create a href link the pop with link of view which returns PDF file as response
when the user clicks on that link the browser will prompt to save the file since it is a file response
from django.http import FileResponse, Http404
def pdf_view(request):
try:
return FileResponse(open('foobar.pdf', 'rb'), content_type='application/pdf')
except FileNotFoundError:
raise Http404()

django zip file doesn't get downloaded

I want to download zip files using Django views. I have gone through many solutions in stack overflow. But the file does not get downloaded at all. Here is the code I am using.
Could anyone, tell me where I am going wrong.
response = HttpResponse(mimetype='application/zip')
response['Content-Disposition'] = 'attachment; filename=%s' % doc[Zip_file_name]
response['X-Sendfile'] = "./Zipfiles" # the path where the zip files are stored
return response
In chrome, If I use inspect element, and double click on the url shown in the network tab, the file gets downloaded as it is recognized as a http get request, whereas on button click nothing happens.
Please Help.
from django.http import HttpResponse
from django.core.servers.basehttp import FileWrapper
# file
response = HttpResponse(FileWrapper(myfile), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response