I have a pdf in my static files, I need to add it some text and let the user download it, but the download part gives me some problems, here is part of my code:
views.py
import io
from werkzeug.wsgi import FileWrapper
from pathlib import Path
from PyPDF2 import PdfFileWriter, PdfFileReader
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from django.http import HttpResponse, FileResponse
def downloadpdf(request):
pdf_path = (Path.home()/"bot"/"mysite"/"static"/"images"/"tesseragenerica.pdf")
# 1
pdf_reader = PdfFileReader(str(pdf_path))
packet = io.BytesIO()
# create a new PDF with Reportlab
can = canvas.Canvas(packet, pagesize=letter)
testo = "text to add" #in future "text to add" will be the username
can.drawString(5, 5, testo)
can.save()
#move to the beginning of the StringIO buffer
packet.seek(0)
new_pdf = PdfFileReader(packet)
# read your existing PDF
existing_pdf = PdfFileReader(open("/home/myusername/bot/mysite/static/images/tesseragenerica.pdf", "rb"))
output = PdfFileWriter()
# add the "watermark" (which is the new pdf) on the existing page
page = existing_pdf.getPage(0)
page.mergePage(new_pdf.getPage(0))
output.addPage(page)
# finally, write "output" to a real file
outputStream = open("destination3.pdf", "wb")
output.write(outputStream)
outputStream.close()
return FileResponse(FileWrapper(packet), as_attachment=True, filename='hello.pdf')
The code for adding text to pdf is correct because in local it works so i think the problem is what i'm putting as the first argument of FileResponse, if I put FileWrapper(packet) for example instead of making me download the file i see this on my browser:
%PDF-1.3 %���� ReportLab Generated PDF document http://www.reportlab.com 1 0 obj << /F1 2 0 R >> endobj 2 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj 3 0 obj << /Contents 7 0 R /MediaBox [ 0 0 612 792 ] /Parent 6 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 4 0 obj << /PageMode /UseNone /Pages 6 0 R /Type /Catalog >> endobj 5 0 obj << /Author (anonymous) /CreationDate (D:20210718122806+00'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20210718122806+00'00') /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (unspecified) /Title (untitled) /Trapped /False >> endobj 6 0 obj << /Count 1 /Kids [ 3 0 R ] /Type /Pages >> endobj 7 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 97 >> stream GapQh0E=F,0U\H3T\pNYT^QKk?tc>IP,;W#U1^23ihPEM_?CW4KISh__N8"+NKVeK&quKrKuB2i9neZ[Kb,ht63StAffBaV~>endstream endobj xref 0 8 0000000000 65535 f 0000000073 00000 n 0000000104 00000 n 0000000211 00000 n 0000000404 00000 n 0000000472 00000 n 0000000768 00000 n 0000000827 00000 n trailer << /ID [<75dce57879667ca53ee6edf7352f4f98><75dce57879667ca53ee6edf7352f4f98>] % ReportLab generated PDF document -- digest (http://www.reportlab.com) /Info 5 0 R /Root 4 0 R /Size 8 >> startxref 1013 %%EOF
Which i think it's a pdf file but can't understand why the browser show me it instead of downloading it. I think (and hope) that i'm close to the solution but i don't know what i'm doing wrong. What can I do to make the pdf downloadable? Thanks
The browser shows the file response if it is a recognizable format to the browser. As browsers recognize it, the browsers shows a preview. If you want to force the user to download it, there is two methods.
First, if you are linking to the download url, add a download attribute to the link from html. <a href="download/example.pdf" download>download me pls</a>
If you want to do it from python, or have to do it in python, then you can return an HttpResponse
object, but with a content_type that forces a download. Example:
def download(request, path):
file_path = os.path.join(settings.MEDIA_ROOT, path)
if os.path.exists(file_path):
with open(file_path, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/force-download")
response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
return response
raise Http404
Resource: Having Django serve downloadable files