django-weasyprint-reports
Reportes PDF genéricos para Django: datos → template HTML → WeasyPrint → PDF → HttpResponse.
- Usa templates normales de Django (sin XML) y WeasyPrint directamente.
- El PDF se genera bajo demanda en memoria: nunca se guarda en disco, en
MEDIA_ROOTni en la base de datos. - No conoce ningún modelo: sirve para cualquiera.
- Incluye una acción Imprimir para los listados del admin.
Requisitos: Python 3.10+, Django 4.2+, WeasyPrint 70+.
Instalación
pip install django-weasyprint-reports
Desde el repositorio: pip install . (o pip install git+<url-del-repo>).
Añade la app a INSTALLED_APPS:
INSTALLED_APPS = [
...
"django.contrib.staticfiles",
"weasyprint_reports",
]
No tiene modelos ni migraciones, no hace falta migrate.
Dependencias del sistema (Pango)
WeasyPrint necesita la librería Pango del sistema operativo. Sin ella aparece
OSError: cannot load library '...libgobject-2.0-0.dll' al generar un PDF.
Compruébalo con python -m weasyprint --info.
Ubuntu / Debian
sudo apt install libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz-subset0
macOS
brew install pango
Windows
-
Instala MSYS2 con las opciones por defecto (
C:\msys64). -
En el shell MSYS2 UCRT64 ejecuta
pacman -S mingw-w64-ucrt-x86_64-pango. -
Si usaste la ruta por defecto no hay que hacer nada más: la app la detecta sola. Si instalaste MSYS2 en otro sitio, indícalo en
settings.py:WEASYPRINT_DLL_DIRECTORIES = r"D:\otra\ruta\ucrt64\bin"
La app antepone esa carpeta al PATH antes de importar WeasyPrint, para que sus DLL ganen a las de
otros programas (p. ej. Tesseract-OCR, que provoca el error 0x7e).
Sin WeasyPrint o sin Pango el proyecto sigue arrancando; el error aparece solo al generar un PDF.
Más detalles: https://doc.courtbouillon.org/weasyprint/stable/first_steps.html
Uso desde una vista
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import get_object_or_404
from weasyprint_reports.pdf import generar_pdf
@login_required
@permission_required("ventas.view_cliente", raise_exception=True)
def reporte_cliente(request, pk):
cliente = get_object_or_404(Cliente.objects.prefetch_related("pedidos"), pk=pk)
return generar_pdf(
template="ventas/cliente_pdf.html", # el nombre lo decide el programador
context={"cliente": cliente},
filename="cliente.pdf",
request=request, # opcional: habilita request/user en el template
)
generar_pdf(template, context=None, *, filename="reporte.pdf", request=None, descargar=False)
devuelve un HttpResponse. Con descargar=True fuerza la descarga; por defecto se muestra en el navegador.
renderizar_pdf(template, context=None, *, request=None) devuelve los bytes (p. ej. para adjuntar a un correo).
Template
{% extends "weasyprint_reports/base.html" %}
{% block header %}Reporte de cliente{% endblock %}
{% block content %}
<h1>{{ cliente.nombre }}</h1>
<table>
<thead><tr><th>Pedido</th><th>Total</th></tr></thead>
<tbody>
{% for p in cliente.pedidos.all %}
<tr><td>{{ p.numero }}</td><td class="num">{{ p.total|floatformat:2 }}</td></tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
weasyprint_reports/base.html define página A4, header y footer repetidos en cada página y "Página X de Y".
Bloques disponibles: title, header, footer, extra_css, content, lang.
Puedes sobrescribir weasyprint_reports/base.html en tu proyecto para poner tu logotipo, colores, etc.
Imágenes y CSS: usa {% static '...' %} (y MEDIA_URL para archivos subidos). Son los únicos
archivos que WeasyPrint puede cargar, además de URIs data:.
Acción "Imprimir" en el admin
from django.contrib import admin
from weasyprint_reports.mixins import ReportAdminMixin
@admin.register(Cliente)
class ClienteAdmin(ReportAdminMixin, admin.ModelAdmin):
report = True
list_display = ("nombre", "email", "activo") # columnas del PDF
En el listado aparece Imprimir en el desplegable de acciones: marcas los registros, pulsas el botón y el PDF se abre en una pestaña nueva (el listado queda como estaba).
Opciones del ModelAdmin:
| Atributo | Por defecto | Descripción |
|---|---|---|
report |
False |
Activa la acción. |
report_template |
weasyprint_reports/admin_list.html |
Template propio; recibe objects y opts. |
report_max |
500 |
Máximo de registros por PDF. |
Para añadir datos a un template propio sobrescribe get_report_context(self, request, queryset).
La acción solo la ven quienes tienen permiso de ver el modelo y solo imprime registros que el admin
les permite ver.
Seguridad
- El nombre del template lo decide siempre el programador, nunca el usuario; no se acepta HTML en bruto.
- Autoescape de Django activo: no uses
|safenimark_safecon datos de usuarios. - WeasyPrint solo carga archivos de
STATIC_URL/MEDIA_URLy URIsdata:. Quedan bloqueadoshttp(s)externo (SSRF),file://y cualquier otro esquema, y se rechaza el path traversal. - Nombre de archivo saneado; respuestas con
Cache-Control: no-store. - Filtra siempre el queryset por lo que el usuario puede ver antes de generar el reporte.
- Generar PDFs consume CPU: limita la frecuencia si el endpoint queda expuesto.
Tests
python manage.py test weasyprint_reports
Son autocontenidos (usan su propio admin y templates en memoria). Los que usan WeasyPrint real se omiten si no está disponible.
Licencia
Copyright (C) 2026 Hector Leal.
Este software es libre y se distribuye bajo los términos de la GNU Lesser General Public License v3.0
o posterior (LGPL-3.0-or-later). Los textos completos están en los archivos
LICENSE (LGPL 3) y COPYING (GPL 3, a la que remite la LGPL).
En la práctica: puedes usar esta librería en proyectos propios o comerciales sin liberar tu código, pero si modificas la propia librería debes publicar esas modificaciones bajo la misma licencia. Esto no es asesoría legal.
Metadata
Release files for django-weasyprint-reports 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| django_weasyprint_reports-0.1.0.tar.gz | 28.7 kB | Without provenance | Details for django_weasyprint_reports-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| django_weasyprint_reports-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for django_weasyprint_reports-0.1.0-py3-none-any.whl |
Total release size: 64.2 kB
Release files / django_weasyprint_reports-0.1.0.tar.gz
| Download URL | django_weasyprint_reports-0.1.0.tar.gz |
|---|---|
| Size | 28.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
177e0e4dc8fa735457e8a4c0aeaaaf416877a5709e7d4ba3ffc9e4c559f7e128
|
|
BLAKE2b-256 checksum How to use checksums |
888f853f25809255973394b628d87f6930354d38dfbf683a1e1fd8e1d73ce339
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|
Release files / django_weasyprint_reports-0.1.0-py3-none-any.whl
| Download URL | django_weasyprint_reports-0.1.0-py3-none-any.whl |
|---|---|
| Size | 35.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5f8a2de508041c342d8935227cd824e3c27841a41071d647305853d4dad202d2
|
|
BLAKE2b-256 checksum How to use checksums |
86ddc0aad75c2f0b59a49bb94fc132d0c2c4b42c9ba15dc0d167c21020757589
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|
Security for django-weasyprint-reports 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.