As a Python developer, I’ve worked on countless projects where generating PDFs dynamically was a must-have feature. One of the most common scenarios is converting an HTML page into a PDF file.
When working with Django, there are several ways to achieve this, but I want to share the methods I’ve found to be the most effective and simple. This tutorial will walk you through converting an HTML page to PDF using Django, complete with code examples and tips to make your PDFs look professional.
Method to Convert HTML to PDF in Django
In many web applications, users expect to download or print content exactly as they see it on the screen. HTML is great for displaying content, but PDFs are the standard for sharing and printing documents because they preserve formatting and layout.
For example, imagine you run a US-based online store that generates invoices after purchase. You want customers to download a nicely formatted invoice PDF that matches the HTML invoice page they see on your site. This is where converting HTML to PDF shines.
Read Pyramid vs. Django
Method 1: Use WeasyPrint to Convert HTML to PDF
One of my favorite tools for this task is WeasyPrint. It’s a powerful library that renders HTML and CSS into PDFs, supporting modern CSS features, which means your PDFs can look just like your web pages.
Step 1: Install WeasyPrint
First, install WeasyPrint and its dependencies:
pip install WeasyPrintOn some systems, you might need additional system packages (like Cairo, Pango) — check WeasyPrint’s documentation if you encounter errors.
Step 2: Create a Django View to Render PDF
Here’s a simple example where I convert an HTML template into a PDF and serve it as a downloadable file.
# views.py
from django.http import HttpResponse
from django.template.loader import get_template
from weasyprint import HTML
def invoice_pdf(request, order_id):
# Simulate fetching order data (replace with your actual data fetching)
order = {
'id': order_id,
'customer_name': 'John Doe',
'items': [
{'name': 'Laptop', 'price': 1200, 'quantity': 1},
{'name': 'Mouse', 'price': 25, 'quantity': 2},
],
'total': 1250
}
# Load your HTML template
template = get_template('invoice.html')
html_content = template.render({'order': order})
# Convert HTML to PDF
pdf_file = HTML(string=html_content).write_pdf()
# Create HTTP response with PDF file
response = HttpResponse(pdf_file, content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="invoice_{order_id}.pdf"'
return responseStep 3: Create the HTML Template
Save this as invoice.html in your templates folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Invoice #{{ order.id }}</title>
<style>
body { font-family: Arial, sans-serif; }
h1 { color: #2c3e50; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.total { font-weight: bold; }
</style>
</head>
<body>
<h1>Invoice #{{ order.id }}</h1>
<p>Customer: {{ order.customer_name }}</p>
<table>
<thead>
<tr>
<th>Item</th><th>Price</th><th>Quantity</th><th>Subtotal</th>
</tr>
</thead>
<tbody>
{% for item in order.items %}
<tr>
<td>{{ item.name }}</td>
<td>${{ item.price }}</td>
<td>{{ item.quantity }}</td>
<td>${{ item.price|floatformat:2|add:"0"|floatformat:2|floatformat:""|add:item.quantity|floatformat:2 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<p class="total">Total: ${{ order.total }}</p>
</body>
</html>I executed the above example code and added the screenshot below.

You can customize this template to match your branding and layout preferences.
Check out Print Django Environment Variables
Method 2: Use xhtml2pdf for HTML to PDF Conversion
Another method I’ve used is xhtml2pdf, which is simpler but supports fewer CSS features compared to WeasyPrint.
Step 1: Install xhtml2pdf
pip install xhtml2pdfStep 2: Django View Example
# views.py
from django.http import HttpResponse
from django.template.loader import render_to_string
from xhtml2pdf import pisa
import io
def render_to_pdf(template_src, context_dict={}):
template = render_to_string(template_src, context_dict)
result = io.BytesIO()
pdf = pisa.pisaDocument(io.BytesIO(template.encode("UTF-8")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
def invoice_pdf(request, order_id):
order = {
'id': order_id,
'customer_name': 'John Doe',
'items': [
{'name': 'Laptop', 'price': 1200, 'quantity': 1},
{'name': 'Mouse', 'price': 25, 'quantity': 2},
],
'total': 1250
}
pdf = render_to_pdf('invoice.html', {'order': order})
if pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="invoice_{order_id}.pdf"'
return response
return HttpResponse("Error generating PDF", status=400)I executed the above example code and added the screenshot below.

The HTML template can be the same as in the WeasyPrint example, but keep in mind some CSS might not render perfectly.
Read Google Authentication in Django
Tips for Better PDF Output
- Use inline CSS or embedded stylesheets for consistent formatting.
- Avoid complex JavaScript or CSS features that PDF converters may not support.
- Test your PDF output on multiple devices to ensure readability.
- For large projects, consider caching generated PDFs for performance.
Generating PDFs from HTML in Django is easy once you pick the right tool. WeasyPrint is my go-to for professional-quality PDFs with rich styling. xhtml2pdf is a good alternative for simpler needs.
With these methods, you can add powerful PDF generation features to your Django apps, enhancing user experience and functionality.
If you want to dive deeper or customize your PDF generation further, feel free to explore the official documentation of these libraries.
You may also like to read other Django tutorials:
- Use Django Built-In Login System
- Build a To-Do List API in Django Rest Framework
- Create a Notes Taking app in Django

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.