Django WeasyPrint Integration
django-weasyprint is a Django application that integrates WeasyPrint, allowing developers to generate PDF documents from HTML and CSS templates within their Django projects. It provides class-based views and response classes to streamline the process of converting rendered Django templates into PDF files. The current version is 2.5.0, with a release cadence tied to major WeasyPrint and Django releases, supporting modern Python and Django versions.
Common errors
-
OSError: dlopen() failed to load a library: cairo / cairo-2
cause WeasyPrint depends on system-level libraries like Cairo and Pango which are not installed via Python's pip. This error typically occurs on Windows, macOS, or Linux if these graphical dependencies are missing or incorrectly configured.fixFollow the official WeasyPrint installation guide for your operating system to install the necessary system dependencies (e.g., GTK+ runtime on Windows, Homebrew for macOS, `apt` packages on Linux). Ensure their paths are correctly set in system environment variables if required. -
Fontconfig error: Cannot load default config file
cause WeasyPrint uses Fontconfig to manage fonts. This error indicates that Fontconfig cannot find its configuration file, often due to missing or improperly configured system font packages or environment variables, especially in headless environments or on Windows.fixInstall `fontconfig` system packages (e.g., `fontconfig` on Linux). On Windows, ensure GTK+ runtime is installed and its `etc/fonts` directory is accessible, or manually configure a `fonts.conf` file and set the `FONTCONFIG_PATH` environment variable. -
NameError: name 'django_url_fetcher' is not defined
cause Attempting to use the old `django_url_fetcher` function after upgrading `django-weasyprint` to version 2.5.0 or later. This function was removed and replaced by a class.fixReplace calls to `django_url_fetcher` with an instance of `DjangoURLFetcher` or a custom class that implements the `WeasyPrint.urlfetcher.URLFetcher` API. Import it using `from django_weasyprint.urlfetcher import DjangoURLFetcher`. -
PDF output not showing images or CSS styles
cause WeasyPrint is unable to resolve the URLs for static assets (images, stylesheets) referenced in your HTML template. This often happens because relative URLs or Django's static URL patterns are not correctly resolved to absolute paths or accessible URLs during PDF generation.fixSet `pdf_baseurl = request.build_absolute_uri('/')` in your `WeasyTemplateResponseMixin` to ensure relative URLs are resolved correctly. For Django static files, ensure `STATIC_URL` is properly configured, `STATIC_ROOT` is collected, and consider implementing a custom `DjangoURLFetcher` if static files are not served via HTTP.
Warnings
- breaking Version 2.5.0 replaced the `django_url_fetcher` function with a `DjangoURLFetcher` class to align with WeasyPrint 68's URLFetcher API. Existing custom URL fetcher implementations using the old function signature will break.
- breaking Version 2.5.0 dropped support for WeasyPrint versions older than 68 and Python versions 3.8 and 3.9.
- breaking Version 2.0.0 required WeasyPrint >= 53.0 and removed `PNGView` and `CONTENT_TYPE_*` constants. This means direct PNG output is no longer supported through `django-weasyprint`.
- gotcha WeasyPrint, the underlying rendering engine, requires external system libraries (like Pango, Cairo, and their GTK+ dependencies) to be installed on the operating system, not just via pip. This is a common source of installation issues, especially on Windows or macOS.
- gotcha Images and CSS stylesheets referenced with relative paths or Django's static/media URLs might not render in the generated PDF unless the `base_url` is correctly configured or a custom URL fetcher is used. WeasyPrint often requires absolute paths or URLs.
Install
-
pip install django-weasyprint
Imports
- WeasyTemplateResponseMixin
from django_weasyprint.views import WeasyTemplateResponseMixin
- WeasyTemplateResponse
from django_weasyprint.views import WeasyTemplateResponse
- DjangoURLFetcher
from django_weasyprint.utils import django_url_fetcher
from django_weasyprint.urlfetcher import DjangoURLFetcher
Quickstart
import os
from django.db import models
from django.shortcuts import render
from django.urls import path
from django.views.generic import DetailView
from django_weasyprint.views import WeasyTemplateResponseMixin, WeasyTemplateResponse
# models.py (example)
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
# views.py
class ProductDetailView(DetailView):
model = Product
template_name = 'products/product_detail.html'
context_object_name = 'product'
class ProductPDFView(WeasyTemplateResponseMixin, ProductDetailView):
# PDF-specific settings
pdf_stylesheets = [
os.path.join(os.environ.get('STATIC_ROOT', ''), 'css/pdf_styles.css')
]
pdf_attachment = True # Forces download
pdf_filename = 'product_details.pdf'
# urls.py (in your app)
# urlpatterns = [
# path('product/<int:pk>/', ProductDetailView.as_view(), name='product_detail'),
# path('product/<int:pk>/pdf/', ProductPDFView.as_view(), name='product_pdf'),
# ]
# products/product_detail.html (example template)
# In your template directory:
# <!DOCTYPE html>
# <html>
# <head>
# <title>{{ product.name }} PDF</title>
# <style>
# @page { size: A4; margin: 2cm; }
# body { font-family: sans-serif; }
# h1 { color: #333; }
# .price { color: green; font-weight: bold; }
# </style>
# <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/pdf_styles.css">
# </head>
# <body>
# <h1>{{ product.name }}</h1>
# <p>{{ product.description }}</p>
# <p class="price">Price: ${{ product.price }}</p>
# </body>
# </html>
# settings.py (important for static files)
# STATIC_URL = '/static/'
# STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')