PDF Generation
π Step-by-Step Guide to Using WeasyPrint in Django
1οΈβ£ Install WeasyPrint
Before using WeasyPrint, install it using pip:
pip install weasyprintWeasyPrint has some system dependencies. If you face installation issues, install the required system packages:
For Ubuntu/Debian:
sudo apt install libpango-1.0-0 libpangocairo-1.0-0 libcairo2 libffi-devFor MacOS:
brew install pango cairo gdk-pixbufFor Windows: - Install GTK+ from WeasyPrintβs documentation.
2οΈβ£ Create a Django View to Generate PDFs
We will create a class-based view (WeasyTemplateResponseMixin) to render a Django template into a PDF.
π Example: Generating a Simple PDF
# views.py
from django.http import HttpResponse
from django.template.loader import get_template
from weasyprint import HTML
import tempfile
def generate_pdf(request):
    """
    Generate a simple PDF from an HTML template.
    """
    template = get_template("pdf_template.html")
    context = {"title": "My PDF Report", "content": "This is a dynamically generated PDF."}
    html_content = template.render(context)
    # Create a temporary file
    with tempfile.NamedTemporaryFile(delete=True) as temp_file:
        HTML(string=html_content).write_pdf(temp_file.name)
        temp_file.seek(0)
        pdf_data = temp_file.read()
    response = HttpResponse(pdf_data, content_type="application/pdf")
    response["Content-Disposition"] = 'inline; filename="report.pdf"'
    return response3οΈβ£ Create an HTML Template for the PDF
WeasyPrint renders HTML and CSS, so we need to define a well-structured HTML template.
π Example: pdf_template.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        h1 {
            color: #333;
        }
        .content {
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>{{ title }}</h1>
    <div class="content">
        <p>{{ content }}</p>
    </div>
</body>
</html>4οΈβ£ Add URL Pattern
Map the PDF generation view in urls.py:
# urls.py
from django.urls import path
from .views import generate_pdf
urlpatterns = [
    path("generate-pdf/", generate_pdf, name="generate_pdf"),
]Now, visiting /generate-pdf/ will return a dynamically generated PDF.
ποΈ Advanced WeasyPrint Usage
1οΈβ£ Generating PDFs with Django Querysets
You can pass database query results into the PDF template.
π Example: Generating a PDF Invoice
# views.py
from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML
from .models import Order
def generate_invoice(request, order_id):
    """
    Generate an invoice PDF for a specific order.
    """
    order = Order.objects.get(id=order_id)
    context = {"order": order}
    html_string = render_to_string("invoice_template.html", context)
    pdf_file = HTML(string=html_string).write_pdf()
    response = HttpResponse(pdf_file, content_type="application/pdf")
    response["Content-Disposition"] = f'filename="invoice_{order.id}.pdf"'
    return responseπ Example: invoice_template.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Invoice</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }
        h1 {
            color: #333;
            border-bottom: 2px solid #000;
            padding-bottom: 10px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 10px;
            text-align: left;
        }
        .total {
            font-weight: bold;
            font-size: 1.2em;
        }
    </style>
</head>
<body>
    <h1>Invoice for Order #{{ order.id }}</h1>
    <p>Customer: {{ order.customer_name }}</p>
    <p>Date: {{ order.date }}</p>
    <table>
        <thead>
            <tr>
                <th>Product</th>
                <th>Quantity</th>
                <th>Price</th>
            </tr>
        </thead>
        <tbody>
            {% for item in order.items.all %}
            <tr>
                <td>{{ item.product_name }}</td>
                <td>{{ item.quantity }}</td>
                <td>${{ item.price }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
    <p class="total">Total Amount: ${{ order.total_price }}</p>
</body>
</html>2οΈβ£ Saving PDFs to Django Models
You can store generated PDFs as files inside a Django model.
π Example: Save Invoice as a File
from django.core.files.base import ContentFile
from weasyprint import HTML
from .models import Order
def save_invoice_pdf(order_id):
    """
    Generate and save a PDF invoice to a model field.
    """
    order = Order.objects.get(id=order_id)
    html_string = render_to_string("invoice_template.html", {"order": order})
    
    pdf_file = HTML(string=html_string).write_pdf()
    
    # Save to model
    order.invoice.save(f"invoice_{order.id}.pdf", ContentFile(pdf_file), save=True)π Update Order Model
from django.db import models
class Order(models.Model):
    customer_name = models.CharField(max_length=100)
    date = models.DateField(auto_now_add=True)
    total_price = models.DecimalField(max_digits=10, decimal_places=2)
    invoice = models.FileField(upload_to="invoices/", blank=True, null=True)  # Store PDFπ¨ Styling PDFs with CSS
WeasyPrint fully supports CSS, including: β
 Fonts
β
 Page Breaks
β
 Headers & Footers
β
 Images
π Example: Adding Page Breaks
@page {
    size: A4;
    margin: 20mm;
}
.page-break {
    page-break-before: always;
}π Usage in HTML
<p>Page 1 content</p>
<div class="page-break"></div>
<p>Page 2 content</p>π Common WeasyPrint Issues & Fixes
| Issue | Solution | 
|---|---|
| no such file or directory: cairo | Install dependencies: sudo apt install libcairo2 | 
| No module named weasyprint | Run pip install weasyprint | 
| Fonts not loading | Use absolute file paths for fonts ( file://URLs) | 
β Summary: Key Takeaways
| Feature | Django Implementation | 
|---|---|
| β Generate PDFs | HTML(string).write_pdf() | 
| β Use Templates | render_to_string("template.html", context) | 
| β Save PDFs to Models | order.invoice.save(...) | 
| β Style with CSS | Full CSS support, including @page | 
π Now you can generate beautifully styled PDFs in Django using WeasyPrint! π