Overview
WeasyPrint is a powerful library that converts HTML/CSS into PDF. Combined with Jinja2 (a templating engine for Python), you can dynamically populate HTML templates with data, then export them to high-quality PDF files.
In this tutorial, you’ll learn how to:
- Set up a minimal project.
- Create a simple Jinja2 HTML template.
- Render the template and generate a PDF using WeasyPrint.
1. Install Dependencies
Make sure you have Python 3.7+ installed, then install the following packages:
pip install weasyprint jinja2
Depending on your operating system, WeasyPrint may require additional dependencies:
- Linux: Make sure
libpango
,libcairo
,librsvg
, etc. are installed. For example (Ubuntu/Debian): bashCopysudo apt-get install libpango-1.0-0 libcairo2 libffi-dev shared-mime-info
- Windows: You may need the MSYS2 environment to install the GTK-based dependencies. Please check the WeasyPrint installation docs for details.
2. Set Up Your Project
Create a simple project structure:
my_weasyprint_project/
├─ templates/
│ └─ example.html
├─ main.py
- templates/example.html will hold our HTML template.
- main.py will be our Python script that handles Jinja2 rendering and WeasyPrint PDF generation.
3. Create the Jinja2 HTML Template
In templates/example.html, let’s create a very simple HTML structure:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My PDF</title>
<style>
/* Basic styling to illustrate PDF rendering */
body {
font-family: Arial, sans-serif;
}
.title {
text-align: center;
margin-top: 40px;
}
.content {
margin: 20px;
}
.footer {
position: fixed;
bottom: 10px;
width: 100%;
text-align: center;
font-size: 0.9em;
color: #777;
}
</style>
</head>
<body>
<div class="title">
<h1>Hello, {{ name }}!</h1>
</div>
<div class="content">
<p>This is a simple PDF generated with WeasyPrint and Jinja2.</p>
<p>Today’s date is: {{ date_str }}</p>
</div>
<div class="footer">
<p>Page rendered at {{ render_time }}</p>
</div>
</body>
</html>
This template uses Jinja2 placeholders like {{ name }}
, {{ date_str }}
, and {{ render_time }}
. We’ll supply these variables from our Python code.
4. Render the Template and Generate the PDF
In main.py, add the following code:
import datetime
from jinja2 import Environment, FileSystemLoader
from weasyprint import HTML
def generate_pdf(name):
# 1. Load Jinja2 environment
env = Environment(loader=FileSystemLoader('templates'))
# 2. Load the template
template = env.get_template('example.html')
# 3. Prepare context (the data we’ll pass to the template)
current_time = datetime.datetime.now()
context = {
'name': name,
'date_str': current_time.strftime('%Y-%m-%d'),
'render_time': current_time.strftime('%H:%M:%S'),
}
# 4. Render HTML
rendered_html = template.render(context)
# 5. Generate PDF from rendered HTML
pdf_file = HTML(string=rendered_html).write_pdf()
# 6. Save PDF to a file
with open('output.pdf', 'wb') as f:
f.write(pdf_file)
print("PDF generated successfully as output.pdf!")
if __name__ == '__main__':
# Provide a sample name to render
generate_pdf("Alice")
Explanation of Key Steps
- Environment & Loader
We useEnvironment
from Jinja2 to load templates from thetemplates/
directory. - Template Rendering
We fetchexample.html
usingget_template('example.html')
. Then we calltemplate.render(context)
with our data dictionary (context
). - WeasyPrint Conversion
We pass the rendered HTML string toHTML(string=rendered_html).write_pdf()
, which returns PDF bytes. - Saving the PDF
We open a fileoutput.pdf
in binary write mode and write the PDF bytes.
5. Run and Test
Run the main.py file:
python main.py
If everything is set up correctly, a new file named output.pdf will appear in your project folder. Open it to see your newly generated PDF!
6. Next Steps and Tips
- Styling: WeasyPrint supports CSS, including page-break properties, custom fonts, etc.
- Images: You can embed images by referencing local files (
<img src="path/to/image.png">
) or using data URLs (base64). - More Complex Templates: Jinja2 supports control structures (
for
,if
, macros, etc.). Use these to handle dynamic lists, conditional rendering, and more advanced templating logic. - Deployment: If you plan to run this on a serverless platform (e.g., AWS Lambda), ensure that all WeasyPrint dependencies are included in your environment.
Conclusion
With just a few lines of code, you can combine Jinja2 templating and WeasyPrint to dynamically generate PDF documents. This workflow is extremely useful for invoicing, reporting, or any scenario where you need to transform HTML content into a professionally formatted PDF.
Feel free to extend this tutorial by adding:
- Custom fonts
- Multi-page layouts
- Page headers/footers
- Tables, charts, or images
Happy coding!