Рендеринг ReportLab pdf, построенного из SimpleDocTemplate
У меня есть приложение django, которое в настоящее время создает pdf файлы, используя холст, который пользователь может загрузить. Я создаю буфер StringIO, делаю некоторые вещи, а затем отправляю вызов response.write.
# Set up response
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=menu-%s.pdf' % str(menu_id)
# buffer
buff = StringIO()
# Create the pdf object
p = canvas.Canvas(buff)
# Add some elements... then
p.showPage()
p.save()
# Get the pdf from the buffer and return the response
pdf = buff.getvalue()
buff.close()
response.write(pdf)
Теперь я хочу построить свой pdf, используя утконос и SimpleDocTemplate, и написал этот
# Set up response
response = HttpResponse(mimetype='application/pdf')
pdf_name = "menu-%s.pdf" % str(menu_id)
response['Content-Disposition'] = 'attachment; filename=%s' % pdf_name
menu_pdf = SimpleDocTemplate(pdf_name, rightMargin=72,
leftMargin=72, topMargin=72, bottomMargin=18)
# container for pdf elements
elements = []
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='centered', alignment=TA_CENTER))
# Add the content as before then...
menu_pdf.build(elements)
response.write(menu_pdf)
return response
Но это не работает, оно создает плохой pdf файл, который нельзя открыть. Я предполагаю, что линия
response.write(menu_pdf)
неверно.
Как сделать PDF?
Ответы
Ответ 1
Ваша ошибка на самом деле довольно простая. Это просто попытка написать неправильную вещь. В вашем коде menu_pdf
не является PDF, а SimpleDocTemplate
, а PDF хранится в pdf_name
, хотя здесь я подозреваю, что pdf_name
- это имя пути, а не файл. Чтобы исправить это, измените свой код на использование файла памяти, как в исходном коде:
# Set up response
response = HttpResponse(mimetype='application/pdf')
pdf_name = "menu-%s.pdf" % str(menu_id)
response['Content-Disposition'] = 'attachment; filename=%s' % pdf_name
buff = StringIO()
menu_pdf = SimpleDocTemplate(buff, rightMargin=72,
leftMargin=72, topMargin=72, bottomMargin=18)
# container for pdf elements
elements = []
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='centered', alignment=TA_CENTER))
# Add the content as before then...
menu_pdf.build(elements)
response.write(buff.getvalue())
buff.close()
return response
Я не уверен, что в документации упоминается использование файловых объектов, а не путей с Platypus, но если вы вникнете в код, вы увидите, что это возможно.
Ответ 2
Для людей, которые работают с python3 и django 1. 7+ необходимо внести некоторые изменения в ответ.
from django.shortcuts import HttpResponse
import io
from reportlab.platypus import SimpleDocTemplate, BaseDocTemplate
def view(request):
buffer = io.BytesIO()
doc = # ... create your SimpleDocTemplate / BaseDocTemplate
# create the usual story
story = []
# ...
doc.build(story)
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=your_name.pdf'
response.write(buffer.getvalue())
buffer.close()
return response