Este documnto explica como gerar arquivos PDF dinamicamente usando “views” Django. Isso é possível através da excelente, biblioteca Python de código-aberto RepostLab .
A vantagem de gerar arquivos PDF dinamicamente é que você pode criar PDFs personalizados para diferentes propósitos – vamos dizer, para diferentes usuários ou diferentes partes de conteúdo.
Por exemplo, o DJango foi usado no kusports.com para gerar relatórios personalizados, prontos para impressão, de pontuação de torneio da NCAA, como arquivos PDF, para pessoas que participam do concurso March Madness.
A biblioteca RepostLab está disponível available on PyPI. Um guia de usuário em user guide (não coincidentemente um arquivo PDF) está disponível para download. Você pode instalar o ReportLab com pip
:
$ pip install reportlab
Teste sua instalação importando no interpretador interativo Python:
>>> import reportlab
Se o comando não emitir nenhum erro, a instalação funciona.
A chave para gerar PDF dinamicamente com Django é que a API do ReportLab atua como um objeto “file-like”, e os HttpResponse
do Django são objetos “file-like”.
Aqui um exemplo “Hello World”:
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
O código e comentário devem ser auto-explanaveis, mas algumas coisas merecem uma menção.
A resposta HTTP tem um tipo MIME especial, application/pdf. Isso indica ao browser que o documento é um arquivo PDF, ao invés de arquivo HTML. Se deixar isso de fora, o browser provavelmente irá interpretar o ontúdo como HTML, o qual deve resultar em uma feia, assustadora “sopa de ltrinhas” no browser.
A resposta HTTP também tem um cabeçalho adicional Content-Disposition
, o qual contém o nome do arquivo PDF. Este nome de arquivo é arbitrário: Chame como quizer. Isso será usado pelo browser na caixa de diálogo “Salvar como...”, etc.
O cabeçalho HTTP Content-Disposition
começa com attachment;
neste exemplo. Isso força o browser a mostrar uma caixa de diálogo perguntando/confirmando como manipular o documento mesmo que exista um padrão definido no computador. Se deixar sem o 'attachment;'
, os browsers usarão qualquer programa/plugin que estejam configurados para usar com PDF. Aqui como o código se parece:
response['Content-Disposition'] = 'filename="somefilename.pdf"'
Acessar a API do ReportLab é fácil: apenas passe o response
como primeiro argumento para canvas.Canvas`. A classe ``Canvas
espera um objeto “file-like”, e os objetos HttpResponse
se encaixam na definição.
Note que todos os métodos subsequentes para geração do PDF são chamados a partir do objeto (neste caso , p
) – e não do response
.
E finalmente, é importante chamar showPage()
e o save()
no arquivo PDF.
Nota
O ReposrtLab não tem mecanismos de segurança para ser usado de maneira concorrente, ou não é thread-safe. Alguns de nossos usuários tem relatado problemas ímpares ao gerar PDF em “views” Django que são acessadas por muitos usuários ao mesmo tempo.
Se estiver contruindo documentos PDFs complexos com o ReportLab, considere usar a bilioteca io
como um lucar temporário de armazenamento do seu arquivo PDF. Essa biblioteca fornece uma objeto “file-like” como interface que é particularmente eficiente. Aqui o mesmo exemplo “Hello World” de antes, reescrito com uso do io
:
from io import BytesIO
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"'
buffer = BytesIO()
# Create the PDF object, using the BytesIO object 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.
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
PDFlib é uma outra bibliotea de geração de PDF que tem API, ou “bindings” para Python. Para usá-lo com o Django, apenas use os mesmos conceitos explanados neste artigo.
XHTML2PDF é ainda uma outra biblioteca para gerar PDF. Ele vêm com um exemplo de como integrá-lo com o Django.
HTMLdoc é um script para a linha de comando que pode converter HTML para PDF. Ele nao tem uma interface para Python. Mas você pode usá-lo acessando o “shell” através do system
ou popen
e retornar a saída para o Python.
Note que não tem muito nestes exemplos que seja especificamente sobre PDF – apenas as partes usando reportlab
. Você pode usar técnicas similares para gerar qualquer outro formato arbitrário para a qual você encontre uma bilioteca Python. Veja também Emitindo CSV com Django para outro exemplo e algumas técnicas que você pode usar quando quiser gerar fomatos baseados em texto.
ago 01, 2016