Cómo generar un PDF HTML en Django paso a paso (con WeasyPrint)

Video thumbnail

Generar un PDF a partir de una plantilla HTML en Django es una necesidad común en cualquier proyecto que deba exportar reportes, facturas o certificados. En esta guía te mostraré cómo hacerlo fácilmente usando WeasyPrint, una librería potente, multiplataforma y muy bien documentada.

¿Por qué generar un PDF en Django?

Convertir una página HTML a PDF desde Django te permite presentar información de manera profesional y exportable sin salir de tu aplicación web.

Casos de uso comunes

  • Facturas y presupuestos automáticos.
  • Reportes de usuarios o ventas.
  • Certificados o comprobantes descargables.
  • Exportación de contenido dinámico, como formularios o listados.

Ventajas de convertir plantillas HTML a PDF

  • Puedes reutilizar tus plantillas existentes de Django.
  • Mantienes un control total sobre el diseño mediante CSS.
  • Los PDFs generados son compatibles con cualquier navegador o sistema.

Instalación de WeasyPrint y dependencias según tu sistema operativo

WeasyPrint es un motor que convierte HTML y CSS en PDF. Su instalación varía según el sistema operativo, ya que requiere algunas librerías externas.

Instalación en Windows

El cual, en el caso de Windows debes de instalar el siguiente programa:

https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases

Instalación en MacOS y Linux

En macOS puedes instalar las dependencias fácilmente con Homebrew:

$ brew install python pango libffi

En la web oficial:

https://doc.courtbouillon.org/weasyprint/stable/

Instalar pip

Una vez instaladas las dependencias, ya puedes instalar el paquete como una dependencia más:

$ pip install weasyprint

Crear una vista para generar un PDF en Django

Con las dependencias listas, vamos a crear una vista que convierta una plantilla HTML en un PDF descargable.

Configuración básica en views.py

Su uso es muy sencillo, basta con usar la función de HTML(), indicando la URL a la cual quieres convertir en HTML y donde lo quieres escribir mediante la función de write_pdf(), en este ejemplo, la URL de Google es la cual vamos a convertir a PDF:

pdfs\views.py

from weasyprint import HTML

def generate_pdf(request):
    filename="documents/archivo.pdf"
    HTML("https://www.google.com.ve/").write_pdf(filename)
    return render(request, 'csv.html')

Y tendremos:

Generar un PDF a partir de una URL
Generar un PDF a partir de una URL

Generar PDF con una plantilla HTML

Supongamos que tienes una plantilla report.html con datos dinámicos.

Podrías adaptar la vista así:

from django.template.loader import render_to_string
from django.http import HttpResponse
from weasyprint import HTML
def generar_pdf(request):
   html_string = render_to_string('report.html', {'usuario': 'María', 'total': 125})
   html = HTML(string=html_string)
   response = HttpResponse(content_type='application/pdf')
   response['Content-Disposition'] = 'inline; filename="reporte.pdf"'
   html.write_pdf(target=response)
   return response

Este paquete permite usar otras opciones como por ejemplo indicar el tamaño de la página:

from weasyprint import HTML, CSS
***
HTML(string='''
<h1>The title</h1>
<p>Content goes here
''').write_pdf(filename)
CSS(string='@page { size: A3; margin: 1cm }')

O definir CSS:

HTML('http://weasyprint.org/').write_pdf('/tmp/weasyprint-website.pdf',
    stylesheets=[CSS(string='body { font-family: serif !important }')])

Todo esto y más lo puedes ver en la documentación oficial; usar esta opción es particularmente útil si el documento PDF que quieres generar es sencillo y puede ser representado mediante un documento HTML; pero, muchas veces esto no es así y necesitas una solución pixel a pixel como veremos a continuación.

Guardar y visualizar el archivo PDF generado

Si prefieres guardarlo en tu servidor:

html.write_pdf(target='media/reportes/reporte.pdf')

Así podrás servirlo desde una URL o adjuntarlo en correos electrónicos.

Personalizar el PDF con CSS y opciones avanzadas

Una de las ventajas de WeasyPrint es su compatibilidad con CSS moderno.

  • Definir tamaño de página y márgenes
    from weasyprint import HTML, CSS
  • HTML('reporte.html').write_pdf('reporte.pdf',
       stylesheets=[CSS(string='@page { size: A4; margin: 1cm }')])
  • Aplicar estilos personalizados con CSS
    CSS(string='body { font-family: "Helvetica"; color: #333; }')

En mi caso, suelo definir un CSS específico solo para impresión, con fuentes y márgenes ajustados.

Recomendaciones para plantillas complejas

Si tu diseño es muy visual (por ejemplo, una factura con logos y tablas), asegúrate de:

Usar rutas absolutas para imágenes y estilos (request.build_absolute_uri()).

Evitar dependencias de JS o frameworks como React en las plantillas renderizadas.

Probar el resultado localmente antes de desplegar.

Alternativas a WeasyPrint: xhtml2pdf y ReportLab

Aunque WeasyPrint es mi favorita, hay más opciones.

Librería    Ventajas    Limitaciones
WeasyPrint    Renderizado preciso, soporte CSS3, multiplataforma    Requiere dependencias externas
xhtml2pdf    Ligera y fácil de instalar    Limitado soporte CSS
ReportLab    Muy potente para PDFs personalizados (gráficos, coordenadas)    No convierte HTML directamente

Usa xhtml2pdf si solo necesitas algo rápido y sin dependencias, o ReportLab si requieres control total del layout (por ejemplo, documentos pixel-perfect).

Errores comunes y cómo solucionarlos

  • Problemas de instalación en Windows
    • Si te aparece “OSError: no library called cairo”, asegúrate de que GTK esté correctamente instalado y agregado al PATH.
  • Rutas relativas y archivos estáticos
    • WeasyPrint necesita rutas absolutas para acceder a imágenes y estilos.
      Ejemplo:
  • HTML(string=html_string, base_url=request.build_absolute_uri())
    • Depuración de estilos que no se aplican
  • WeasyPrint solo interpreta CSS válido. Verifica las hojas de estilo con herramientas como CSS Validator.

Conclusión

Generar un PDF HTML en Django es mucho más fácil de lo que parece si usas las herramientas adecuadas.
En mi caso, WeasyPrint me ha permitido generar PDFs estables, bien formateados y multiplataforma, con mínima configuración.

Si necesitas precisión absoluta (por ejemplo, documentos fiscales), puedes explorar alternativas como ReportLab, pero para la mayoría de proyectos Django, WeasyPrint es más que suficiente.

Preguntas frecuentes

  • ¿Cuál es la mejor librería para generar PDF en Django?
    • Depende del caso. WeasyPrint ofrece el mejor balance entre potencia y simplicidad.
  • ¿Cómo aplicar estilos CSS al PDF generado?
    • Añadiendo una hoja de estilos mediante el parámetro stylesheets de write_pdf().
  • ¿Se puede generar un PDF desde una plantilla HTML en Django?
    • Sí, es la forma más práctica: renderizas la plantilla con render_to_string() y luego la conviertes con WeasyPrint.
  • ¿Qué diferencias hay entre WeasyPrint y xhtml2pdf?
    • xhtml2pdf es más simple pero con soporte CSS limitado. WeasyPrint ofrece compatibilidad con CSS3 y resultados más fieles.

Acepto recibir anuncios de interes sobre este Blog.

Vamos a aprender a generar un PDF a partir de un HTML en Django empleando el plugin weasyprint.

| 👤 Andrés Cruz

🇺🇸 In english