Gerando PDFs com o Django

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.

Instalar o ReportLab

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.

Escreva sua “view”

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.

PDFs complexos

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

Outras fontes

  • 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.

Outros Formatos

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.

Back to Top