Stack Overflow Asked by Piethon on August 8, 2020
I have two working PDF generating views. I would like to create a view that combines these two views & merges the output PDFs produced by the two views to generate one PDF containing the output PDFs of the two views.
I would also like to specify that these two views use different approaches to generate PDFs. The first one renders an HTML template to create PDF & the second creates a PDF from scratch using Reportlab.
I am new to Django, How can I do this?
View 1
class GenerateAllDocs(View):
def allDocGen(request):
if request.method == 'POST':
all_doc_gen_form = GenerateAllForms(request.POST)
if all_doc_gen_form.is_valid():
some_Field_1= all_doc_gen_form.cleaned_data['some_Field_1']
some_Field_2= all_doc_gen_form.cleaned_data['some_Field_2']
template = get_template('PDF_templates/att_pg_pdf_template.html')
data = {
'some_Field_1': some_Field_1,
'some_Field_2': some_Field_2,
}
html = template.render(data)
pdf = render_to_pdf('PDF_templates/att_pg_pdf_template.html', data)
if pdf:
response = HttpResponse(pdf, content_type = 'application/pdf')
filename = "something - %s.pdf" %(data.get('zzzzz'))
content = "inline; filename=%s" %(filename)
download = request.GET.get('download')
if download:
content = "attachment; filename%s" %(filename)
response['Content-Disposition'] = content
return response
return HttpResponse('Not Found')
all_doc_gen_form = GenerateAllForms()
return render(request, 'form_UI_templates/pg_att_form_UI_template.html', {'all_doc_gen_form':all_doc_gen_form})
View 2
def template_PDF_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; inline; filename="somefilename.pdf"'
buffer = BytesIO()
# Create the PDF object, using the BytesIO object as its "file."
p = canvas.Canvas(buffer, pagesize=letter)
# Draw things on the PDF. Here's where the PDF generation happens.
p.drawImage('D:/worrk/PyDjango/mysite - PROD VERSION/main/static/images/cerfaImg.jpg',0,0, width=8.27 * inch, height= 11.69 * inch)
p.drawString(40, 724, " ".join('XX-XXX-XX'.replace('-','').upper())) # car_licence_plate
p.drawString(193, 149, 'hello 123') # address_city
# 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
EDIT #1
Following suggestion by ktowen, here is my updated code. I created a function based view for my view 2 and call that function inside of view 1 & then attempt to merge the two PDFs created by the views. This still doesn’t work – error message is written after code.
def create_cerfa(request):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
buffer_1 = BytesIO()
p = canvas.Canvas(buffer_1)
p.drawImage('D:/worrk/PyDjango/mysite - PROD VERSION/main/static/images/cerfaImg.jpg',0,0, width=8.27 * inch, height= 11.69 * inch)
p.drawString(40, 724, " ".join('AZ-343-BT'.replace('-','').upper()))
p.drawString(178, 724, " ".join('VF77JNFUC9J177958').upper())
p.save()
pdf = buffer_1.getvalue()
buffer_1.close()
response.write(pdf)
return response
def createAttestation(request):
if request.method == 'POST':
all_doc_gen_form = GenerateAllForms(request.POST)
if all_doc_gen_form.is_valid():
data1 = all_doc_gen_form.cleaned_data['data1']
data12 = all_doc_gen_form.cleaned_data['data12']
template = get_template('PDF_templates/att_pg_pdf_template.html')
data = {
'data1': data1,
'data12': data12,
}
html = template.render(data)
pdf = render_to_pdf('PDF_templates/att_pg_pdf_template.html', data)
cerfa = create_cerfa(request)
pdf1resp = HttpResponse(pdf, content_type = 'application/pdf')
pdf2resp = HttpResponse(cerfa, content_type = 'application/pdf')
pdfs = [pdf1resp, pdf2resp]
merger = PdfFileMerger()
for item in pdfs:
merger.append(item)
merger.write()
if pdf:
response = HttpResponse(merger, content_type = 'application/pdf')
return response
all_doc_gen_form = GenerateAllForms()
return render(request, 'form_UI_templates/pg_att_form_UI_template.html', {'all_doc_gen_form':all_doc_gen_form})
Error Message
Traceback (most recent call last):
File "C:UsersWorkAppDataLocalProgramsPythonPython38-32libsite-packagesdjangocorehandlersexception.py", line 34, in inner
response = get_response(request)
File "C:UsersWorkAppDataLocalProgramsPythonPython38-32libsite-packagesdjangocorehandlersbase.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:UsersWorkAppDataLocalProgramsPythonPython38-32libsite-packagesdjangocorehandlersbase.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:worrkPyDjangomysite - PROD VERSIONmainviews.py", line 460, in createAttestation
merger.append(item)
File "C:UsersWorkAppDataLocalProgramsPythonPython38-32libsite-packagesPyPDF2merger.py", line 203, in append
self.merge(len(self.pages), fileobj, bookmark, pages, import_bookmarks)
File "C:UsersWorkAppDataLocalProgramsPythonPython38-32libsite-packagesPyPDF2merger.py", line 133, in merge
pdfr = PdfFileReader(fileobj, strict=self.strict)
File "C:UsersWorkAppDataLocalProgramsPythonPython38-32libsite-packagesPyPDF2pdf.py", line 1084, in __init__
self.read(stream)
File "C:UsersWorkAppDataLocalProgramsPythonPython38-32libsite-packagesPyPDF2pdf.py", line 1689, in read
stream.seek(-1, 2)
Exception Type: AttributeError at /tst2/
Exception Value: 'HttpResponse' object has no attribute 'seek'
EDIT #2
So I’ve narrowed down the problem to the actual code of merging the PDFs. I tested the approach given in EDIT 2 by ktowen.
I commented the merging part and then returned the PDFs as follows
return FileResponse(pdf1, as_attachment=True, content_type='application/pdf')
I checked it with PDF1 & PDF2 – Both are getting generated, but I don’t understand what is wrong with the merging part? & how can I fix it?
EDIT #3
Here’s my Render to PDF function
from __future__ import print_function
from io import BytesIO
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf import pisa
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
You can extract the pdf generation logic to two functions and use PyPDF2 PdfFileMerger to merge the two pdfs.
This is the general idea:
from PyPDF2 import PdfFileMerger
def merged_PDF_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; inline; filename="somefilename.pdf"'
pdf1_buffer = get_pdf1()
pdf2_buffer = get_pdf2()
pdf_merger = PdfFileMerger()
pdf_merger.append(pdf1_buffer)
pdf_merger.append(pdf2_buffer)
# This can probably be improved
pdf_merger.write(buffer)
pdf_merger.close()
buffer.seek(0)
response.write(buffer.getvalue())
return response
EDIT 1 Try with this
class WillThisWork(View): # I hope so :|
def merged_PDF(request):
buffer = BytesIO()
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; inline; filename="somefilename.pdf"'
pdf1_buffer = createAttestation(request)
pdf2_buffer = create_cerfa(request)
pdf_merger = PdfFileMerger()
pdf_merger.append(pdf1_buffer)
pdf_merger.append(pdf2_buffer)
pdf_merger.write(buffer)
pdf_merger.close()
buffer.seek(0)
return FileResponse(buffer, as_attachment=True, filename='hello.pdf')
EDIT 2 Based in your edit try this
def create_cerfa_pdf():
filestream = BytesIO()
p = canvas.Canvas(filestream)
p.drawImage('D:/worrk/PyDjango/mysite - PROD VERSION/main/static/images/cerfaImg.jpg',0,0, width=8.27 * inch, height= 11.69 * inch)
p.drawString(40, 724, " ".join('AZ-343-BT'.replace('-','').upper()))
p.drawString(178, 724, " ".join('VF77JNFUC9J177958').upper())
p.save()
filestream.seek(0)
return filestream
def create_cerfa(request):
pdf = create_cerfa_pdf()
return FileResponse(pdf, as_attachment=True, filename="somefilename.pdf")
def createAttestation(request):
if request.method == 'POST':
all_doc_gen_form = GenerateAllForms(request.POST)
if all_doc_gen_form.is_valid():
data1 = all_doc_gen_form.cleaned_data['data1']
data12 = all_doc_gen_form.cleaned_data['data12']
template = get_template('PDF_templates/att_pg_pdf_template.html')
data = {
'data1': data1,
'data12': data12,
}
html = template.render(data)
pdf1 = render_to_pdf('PDF_templates/att_pg_pdf_template.html', data)
pdf2 = create_cerfa_pdf()
merger = PdfFileMerger()
for item in [pdf1, pdf2]:
merger.append(item)
filestream = BytesIO()
merger.write(filestream)
merger.close()
filestream.seek(0)
return FileResponse(filestream, as_attachment=True)
all_doc_gen_form = GenerateAllForms()
return render(request, 'form_UI_templates/pg_att_form_UI_template.html', {'all_doc_gen_form':all_doc_gen_form})
Answered by ktowen on August 8, 2020
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP