Новым читателям я был бы очень признателен, если бы вы предложили, как я могу улучшить свой вопрос. Спасибо!
У меня есть два рабочих представления для создания PDF. Я хотел бы создать представление, которое объединяет эти два представления и объединяет выходные PDF-файлы, созданные двумя представлениями, для создания одного PDF-файла, содержащего выходные PDF-файлы двух представлений. Я также хотел бы указать, что эти два представления используют разные подходы для создания PDF-файлов. Первый отображает шаблон HTML для создания PDF-файла, а второй создает PDF-файл с нуля с помощью Reportlab. Я новичок в Django, как я могу это сделать?
Просмотр 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})
Просмотр 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
РЕДАКТИРОВАТЬ # 1 Следуя предложению ktowen , вот мой обновленный код. Я создал представление на основе функций для своего представления 2 и вызвал эту функцию внутри представления 1, а затем попытался объединить два PDF-файла, созданных представлениями. Это по-прежнему не работает - сообщение об ошибке пишется после кода.
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})
Сообщение об ошибке
Traceback (most recent call last):
File "C:\Users\Work\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\Work\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\Work\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\worrk\PyDjango\mysite - PROD VERSION\main\views.py", line 460, in createAttestation
merger.append(item)
File "C:\Users\Work\AppData\Local\Programs\Python\Python38-32\lib\site-packages\PyPDF2\merger.py", line 203, in append
self.merge(len(self.pages), fileobj, bookmark, pages, import_bookmarks)
File "C:\Users\Work\AppData\Local\Programs\Python\Python38-32\lib\site-packages\PyPDF2\merger.py", line 133, in merge
pdfr = PdfFileReader(fileobj, strict=self.strict)
File "C:\Users\Work\AppData\Local\Programs\Python\Python38-32\lib\site-packages\PyPDF2\pdf.py", line 1084, in __init__
self.read(stream)
File "C:\Users\Work\AppData\Local\Programs\Python\Python38-32\lib\site-packages\PyPDF2\pdf.py", line 1689, in read
stream.seek(-1, 2)
Exception Type: AttributeError at /tst2/
Exception Value: 'HttpResponse' object has no attribute 'seek'
EDIT # 2
Итак, я сузил проблему до фактического кода слияния PDF-файлов. Я протестировал подход, приведенный в EDIT 2 by ktowen.
Я прокомментировал часть слияния, а затем вернул PDF-файлы следующим образом:
return FileResponse(pdf1, as_attachment=True, content_type='application/pdf')
Я проверил это с помощью PDF1 и PDF2 - оба генерируются, но я не понимаю, что не так с частью слияния? и как это исправить?
Незначительное редактирование - # 2.1 Вот моя функция рендеринга в PDF
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
EDIT # 3 Здесь я изменил определение PDF внутри функции render_to_pdf следующим образом.
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
pdf = result.getvalue()
Теперь ошибка 'utf-8' codec can't decode byte 0x93 in position 10: invalid start byte
Поэтому, чтобы устранить эту ошибку, я попытался изменить кодировку внутри функции render_to_pdf . Поскольку я много использую французский язык в этом проекте, я протестировал рекомендуемые кодировки, такие как latin1 , UTF-8 и значение по умолчанию ISO-8859-1 , но все равно получаю та же ошибка.
Ниже приводится полное сообщение об ошибке
Traceback (most recent call last):
File "C:\Users\Work\AppData\Roaming\Python\Python38\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\Work\AppData\Roaming\Python\Python38\site-packages\django\core\handlers\base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\worrk\PyDjango\mysite - PROD VERSION\main\views.py", line 596, in createAttestation
pdf1 = PdfFileReader(open(p1,'rb'))
Exception Type: UnicodeDecodeError at /tst2/
Exception Value: 'utf-8' codec can't decode byte 0x93 in position 10: invalid start byte