Django : Downloading PDF object generated by the library FPDF - python

I have a view that contains a wizard form. When the form is submitted, a httpresponse is sent with a PDF file. I generate the PDF file with the FPDF2 Library from the data got in the form submitted by the user.
To be sure that the PDF class using this library works, I tested it in a simple python script.
EDITED
My problem comes from the pdf that I download, I can not open it because no data is stored in it. I open it with the "Note" software and there is just an "None" written inside.
So how can I send the data of the pdf object to the Httpresponse ?
Here is my code :
class FormWizardQR(SessionWizardView):
template_name = "invoices/qr.html"
form_list = [FormStepOneBeneficiary, FormStepTwoPaymentInfos, FormStepThreeDebtor]
def done(self, form_list, **kwargs):
# GET DATA FROM FORMS
form_data = dict(ChainMap(*[form.cleaned_data for form in form_list]))
# PREPARE DATA FOR QR-PDF GENERATOR
list_str_pay_to = []
list_str_pay_by = []
reference = form_data.get('ref_number')
pdf = PDF('portrait', 'mm', 'A4')
pdf.set_margins(left=0, top=0, right=0)
pdf.add_page()
pdf.border_bill()
pdf.r_title("Récépissé")
pdf.r_zone_indications(reference=reference, list_str_pay_to=list_str_pay_to, list_str_pay_by=list_str_pay_by)
pdf.output(name="myfilename.pdf", dest="S")
print(type(pdf))
print(pdf)
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = "attachment; filename=myfilename.pdf"
return response
Thank you

According to the documentation of the last version of pyFPDF2 (version 2.5.7) : https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.output
The dest is DEPRECATED and "By default the bytearray buffer is returned. If a name is given, the PDF is written to a new file."
So it just needs :
response = HttpResponse(bytes(pdf.output()), content_type='application/pdf')
response['Content-Disposition'] = "attachment; filename=myfilename.pdf"
return response

Related

pdf file doesn't save in Django

I use Django 2.1.4 and use Django sample for create pdf report
def some_view(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)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
# FileResponse sets the Content-Disposition header so that browsers
# present the option to save the file.
return FileResponse(buffer, as_attachment=True, filename='hello.pdf')
It started dowloaded but never finished. What is wrong?
Old version works properly
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
# Create the PDF object, using the response object as its "file."
p = canvas.Canvas(response)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
return response
I would look at this example (except for the queryset),, see if that works, similar worked for me earlier today, How can i display my data in database and export it to pdf -Django
Get the value of the BytesIO buffer and write it to the response.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="WishList.pdf"'
from reportlab.pdfgen import canvas
buffer = BytesIO()
p = canvas.Canvas(buffer)
p.drawString(100, 100, "Hello world.")
p.showPage()
p.save()
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
Believe it or not, the old version is the way I recommend that you do it. To get this working with a FileResponse, try the below:
# FileResponse sets the Content-Disposition header so that browsers
# present the option to save the file.
response = FileResponse(buffer, as_attachment=True, filename='hello.pdf', content_type='application/pdf')
# set the content length to let the browser know how many bytes to expect
response['Content-Length'] = bugger.getbuffer().nbytes
return response

Serving pdf files by link, downloaded as pdf.html

Crated function to allow users download pdf files by link. Works fine, the only problem that what user save is .html. So all files are file.pdf.html.
def download(request,ticket_id):
ticket_path = str(Ticket.objects.get(id=ticket_id).upload)
with open('files/media/' + ticket_path, 'rb') as pdf:
response = HttpResponse(pdf.read())
response['content_type'] = 'application/pdf'
response['Content-Disposition'] = 'attachment;filename="file.pdf"'
return response
Why?
You should move content_type into HttpResponse(pdf.read(), content_type='application/pdf'), it's an attribute of HttpResponse

How can i display my data in database and export it to pdf -Django

my x variable is getting all the data in my database, i guess? someone help me how can i display all data and export it to pdf file.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="WishList.pdf"'
buffer = BytesIO()
# Create the PDF object, using the BytesIO object as its "file."
p = canvas.Canvas(buffer)
x = Item.objects.all()
p.drawString(100, 100,x)
p.drawString(200,300,"sad")
# Close the PDF object cleanly.
p.showPage()
p.save()
# Get the value of the BytesIO buffer and write it to the response.
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
Your variable x won't return anything you can print into the PDF, because its a queryset and not a couple strings attached to each other. I just started working with Django and getting the values works something like this:
x = Item.objects.all[0].name
This code snippet will assign the vale of the row name of the first entry in your Item table to the variable x.
For more Information I can only recommend reading the Tutorial about writing queries on the django website.

Django Change File name in PDF export

I found this handy code in the Django Docs:
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
# Create the PDF object, using the response object as its "file."
p = canvas.Canvas(response)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
return response
I would like to pass a variable to the function as variable name, but cannot figure it out (though I am sure it is super easy).
Anyone have an idea?
Thanks so much!
filename="somefilename.pdf" there is place where you can determine your filename.
You can use it as:
filename = 'somefilename.pdf'
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
Hope it might helps you:
Add one more argument named "name" to the view "some_view" and replace the filename with the argument value.
def hello_pdf(request, name):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=%s.pdf'% name
temp = StringIO()
# Create the PDF object, using the StringIO object as its "file."
p = canvas.Canvas(temp)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly.
p.showPage()
p.save()
# Get the value of the StringIO buffer and write it to the response.
response.write(temp.getvalue())
return response
Check the name argument replacing the filename in the 4th line of code. Also don't forget to update the urls.py like below:
url(r'^(?P<name>\w+)/$', 'app.some_view')
After all pass the filename you wish to replace with url like below:
http://yourwebsite.com/name-of-file/
If you want to force viewing the PDF in browser with given filename but without automatic download, you can use "inline" instead of "attachment":
response["Content-Disposition"] = f'inline; filename="{file_name}"'

How can i make the common function/view for servinf downloadble files in django python

I am displaying the list of objects in the html table.
i have the download link in front of every row which i want them to download the linked file.
I have made this function
def make_downloadable_link(path):
#Prepare the form for downloading
wrapper = FileWrapper(open(mypath))
response = HttpResponse(wrapper,'application/pdf')
response['Content-Length'] = os.path.getsize(mypath)
fname = mypath.split('/')[-1]
response['Content-Disposition'] = 'attachment; filename= fname'
return response
This is working fine if i use it for hard coded path in view for single file. But i want to make a generic view so that it works on all the files in the table
I hav the path of the file avaiable in object.path variable but i am confused how can i pass the path object to the downlaod file view. because i want to hide that actual path from the user.
I don't know what to write in the URLs.py file fo that download file view
What would you like to do is get actual file path from object. And as you have said the file path is stored in object.path that makes it easy.
For example:
urls.py
url(r'^download/(?P<object_id>\d+)/$', "yourapp.views.make_downloadable_link", name="downloadable")
In views.py:
def make_downloadable_link(object_id):
# get object from object_id
object = ObjectModel.objects.get(id=object_id)
mypath = object.path
#prepare to serve the file
wrapper = FileWrapper(open(mypath))
response = HttpResponse(wrapper,'application/pdf')
response['Content-Length'] = os.path.getsize(mypath)
fname = mypath.split('/')[-1]
response['Content-Disposition'] = 'attachment; filename= fname'
return response

Categories