Este documento explora como exportar arquivos PDF dinamicamente usando views do Django. Isso é possível graças a uma excelente, biblioteca PDF de código-aberto para Python, chamada ReportLab.
A vantagem de gerar dinamicamente arquivos PDF é que você pode criar PDFs customizados para diferentes propósitos – como para diferentes usuários ou diferentes partes de conteúdos.
Por exemplo, o Django foi usado no kusports.com para gerar versões de impressão curtomizadas dos torneios do NCAA, como arquivos PDF, para pessoas participantes no concurso March Madness.
Baixe e instale a biblioteca ReportLab do site http://www.reportlab.org/oss/rl-toolkit/download/. O guia de usuário (não coincidentemente, um arquivo PDF) explica como instalá-lo.
Teste sua instalação importando-o no interpretador interativo do Python:
>>> import reportlab
Se o comando não mostrar nenhum erro, a instalação está funcionando.
A chave para gerar PDFs dinamicamente com o Django é que a API do ReportLab trabalha sobre objetos que se comportam como arquivos, e objetos HttpResponse do Django são objetos assim.
Aqui vai um exemplo "Hello World":
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Crie o objeto HttpResponse com o cabeçalho de PDF apropriado.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'
# Crie o objeto PDF, usando o objeto response como seu "arquivo".
p = canvas.Canvas(response)
# Desenhe coisas no PDF. Aqui é onde a geração do PDF acontece.
# Veja a documentação do ReportLab para a lista completa de
# funcionalidades.
p.drawString(100, 100, "Hello world.")
# Feche o objeto PDF, e está feito.
p.showPage()
p.save()
return response
O código e comentários devem ser auto-explicativos, mas umas poucas coisas merecem ser mencionadas:
O response recebe um mimetype especial, application/pdf. Isso informa ao navegador que o documento é um arquivo PDF, em vez de um arquivo HTML. Se você não informar isto, o navegador irá provavelmente interpretar a saída como um HTML, o que poderia resultar em um resultado feio e assustador na janela do navegador.
O response recebe um cabeçalho adicional Content-Disposition, que contém o nome do arquivo PDF. Esse nome de arquivo é arbitrário: chame-o como quiser. Ele será usado pelo navegador na caixa de diálogo "Salvar como...", etc.
O cabeçalho Content-Disposition começa com 'attachment; ' neste exemplo. Isso força o navegador a mostrar uma caixa de diálogo avisando/confirmando como manipular o documento, mesmo se um padrão está definido na máquina. Se você não informar o 'attachment', o navegador manipulará o PDF usando qualquer programa/plugin que ele tiver configurado para usar com PDFs. Veja como esse código se pareceria:
response['Content-Disposition'] = 'filename=algum_nomedearquivo.pdf'
Usar hooks da API do ReportLab é fácil: somente passe response como o primeiro argumento para o canvas.Canvas. A classe Canvas recebe um objeto como arquivo, e objetos HttpResponse atendem a esse requisito.
Note que todo método subseqüente de geração de PDF é chamado no objeto PDF (neste caso, p) -- não no response.
Finalmente, é importante chamar showPage() e save() sobre o arquivo PDF.
Se você está criando um documento PDF complexo com o ReportLab, considere a utilização da biblioteca cStringIO como um manipulador temporário para o seu arquivo PDF. A biblioteca cStringIO fornece uma interface para objeto como arquivo que é particularmente eficiente. Aqui o exemplo acima "Hello World" é re-escrito para usar o cStringIO:
# Fall back to StringIO in environments where cStringIO is not available
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Crie o objeto HttpResponse com o cabeçalho PDF apropriado.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'
buffer = StringIO()
# Crie um objeto PDF, usando o objeto StringIO como seu "arquivo."
p = canvas.Canvas(buffer)
# Desenhe coisas no PDF. Aqui é onde a geração do PDF acontece.
# Veja a documentação do ReportLab para a lista completa de
# funcionalidades.
p.drawString(100, 100, "Hello world.")
# Feche o objeto PDF.
p.showPage()
p.save()
# Pegue o valor do buffer StringIO e escreva-o para o response.
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
Repare que não há muitos destes exemplos específicos de PDF -- somente o que é usado o reportlab. Você pode usar uma técnica similar para gerar qualquer formato que possa ser gerado por uma biblioteca Python. Também veja Exportando CSV com o Django para outro exemplo e algumas técnicas que você pode usar quando gera formatos baseados em texto.
Dec 26, 2011