Generar un fichero PDF usando Fast API

Tiempo de lectura: 2 minutos

Hoy os voy a explicar cómo podemos generar un PDF a partir de un HTML y usando FAST API.

Lo primero que vamos a necesitar es instalar las librerías necesarias. En este caso vamos a usar wkhtmltopdf (https://wkhtmltopdf.org/) y PDFKIT de Python (https://pdfkit.org/)

Ahora vamos a instalar wkhtmltopdf, si usamos ubuntu o linux utilizaremos este comando:

apt-get install xvfb libfontconfig wkhtmltopdf -y 

Y para instalar PDFKIT:

pip install pdfkit

Una vez instalado, vamos a instalar también un motor de plantillas html Jinja2 (https://palletsprojects.com/p/jinja/). No es necesario hacerlo, ya que podemos generar el HTML con texto plano, pero para mayor facilidad en diseño del PDF recomiendo utilizarlo y seguir las instrucciones.:

pip install -U Jinja2

Una vez instalado, ya tenemos listo el entorno.

Ahora vamos a crear el código. Para ello vamos a crear un objeto auxiliar que realice las operaciones de PDF, lo voy a llamar pdf.py:

import pdfkit
from jinja2 import Environment, FileSystemLoader

def generarPDF() -> str:
    env = Environment(loader=FileSystemLoader('.'))
    
    # opciones de configuración para wkhtmltopdf
    options = {
        'page-size': 'Letter',
        'margin-top': '0.75in',
        'margin-right': '0.75in',
        'margin-bottom': '0.75in',
        'margin-left': '0.75in'
    }
    
    template = env.get_template("templates/template_pdf.html")
    # define las variables que se van a reemplazar en la plantilla
    variables = {
        'nombre': 'Juan',
        'apellido': 'Pérez',
        'edad': 30
    }
    
    html = template.render(variables)
    
    return pdfkit.from_string(html, False, options=options)
    
 

En este ejemplo tenemos un template_pdf.html que se va a rellenar usando Jinja2 con las variables de ejemplo. Después se transformará a PDF y se devolverá en la función.

Ahora creamos el archivo html dentro de templates/template_pdf.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>PDF Ejemplo Persona</title>
</head>
<body>
    <h1>Anexo de alumno</h1>
    <p>Nombre: {{ nombre }}</p>
    <p>Apellido: {{ apellido }}</p>
    <p>Edad: {{ edad }}</p>
</body>
</html>

Este template, recibe 3 variables (nombre, apellido, edad) y se construirá usando Jinja2.

Ahora creamos un route para obtener el PDF, no voy a crear el código entero, para ello puedes revisar la sección de FastAPI para saber como crear un POST (https://devcodelight.com/crear-un-api-rest-usando-fast-api-ejemplo-sin-conexion-a-base-de-datos/):

from pdf import generarPDF

@app.get("/obtener_pdf/", status_code=status.HTTP_200_OK)
def create_pdf ( db_session: Session = Depends(get_db)) -> Response:

    pdf = generarPDF()
    
    headers = {'Content-Disposition': 'attachment; filename="data.pdf"'}
    return Response(pdf, headers=headers, media_type='application/pdf')

Ahora hemos importado la funcion generarPDF desde nuestro objeto: from pdf import generarPDF

Y generamos el pdf, después lo devolvemos como un fichero descargable (attachment) con nombre data.pdf.

Deja un comentario