Automating PDF Reports with ReportLab: A Professional Solution for Developers

Python tutorial - IT technology blog
Python tutorial - IT technology blog

Why You Should Stop Creating Reports Manually

Copying data from Excel, pasting it into Word, and then struggling with margins to export a PDF is an incredibly time-consuming process. I once spent an entire morning just creating a sales report, only to have to start over because of a single typo.

If you’re already using Python to crawl data or run automation scripts, your reporting should be automated as well. ReportLab is the key to solving this problem once and for all.

Unlike HTML-to-PDF libraries that often suffer from formatting issues, ReportLab allows you to “draw” directly onto the page. You have absolute control over every pixel. This library is perfect for generating invoices, certificates, or data analysis reports that require high precision.

Environment Setup

It takes less than 10 seconds to install ReportLab via pip. For the best support in chart rendering and image processing, you should also install the Pillow library:

pip install reportlab pillow

Important Note: By default, ReportLab does not support Vietnamese Unicode. Without font configuration, accented characters will appear as error boxes. You need to have a .ttf font file (e.g., Arial or Roboto) ready in your project directory to integrate into your code.

Configuring Core Components

ReportLab offers two approaches: Canvas (manual drawing using x, y coordinates) and Platypus (a high-level layout framework). I recommend using Platypus. It works like stacking content blocks and automatically handles page breaks when data is too long.

1. Handling Fonts and Styles

The first step is to register the font so the report displays correctly. This step helps you avoid 99% of the most common display errors.

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER

# Register font to display Vietnamese
try:
    pdfmetrics.registerFont(TTFont('Arial', 'arial.ttf'))
except:
    print("Error: arial.ttf file not found. Please check the directory!")

styles = getSampleStyleSheet()
title_style = ParagraphStyle(
    'CustomTitle',
    parent=styles['Heading1'],
    fontName='Arial',
    fontSize=20,
    alignment=TA_CENTER,
    spaceAfter=30
)

2. Building Flexible Tables

Tables are the most important part of any report. With TableStyle, you can format colors, borders, and alignment as professionally as in Excel.

from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors

# Sample data for the report
data = [
    ['No.', 'Product', 'Quantity', 'Revenue'],
    ['1', 'Management Software', '50', '5,000$'],
    ['2', 'Python Course', '120', '12,000$'],
    ['3', 'Cloud Services', '30', '3,000$'],
]

table = Table(data, colWidths=[40, 180, 80, 100])
table.setStyle(TableStyle([
    ('BACKGROUND', (0, 0), (-1, 0), colors.dodgerblue),
    ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
    ('FONTNAME', (0, 0), (-1, -1), 'Arial'),
    ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
    ('BOTTOMPADDING', (0, 0), (-1, 0), 10),
]))

3. Drawing Sharp Vector Charts

Instead of inserting pixelated bitmap images, use ReportLab’s graphics module. Charts will be drawn as vectors, keeping the file size small and ensuring they remain sharp when printed.

from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart

def create_chart():
    drawing = Drawing(400, 200)
    bc = VerticalBarChart()
    bc.x = 50
    bc.y = 50
    bc.height = 125
    bc.width = 300
    bc.data = [(50, 120, 30)]
    bc.categoryAxis.categoryNames = ['Product A', 'Product B', 'Product C']
    bc.valueAxis.valueMin = 0
    bc.valueAxis.valueMax = 150
    drawing.add(bc)
    return drawing

Finalizing the PDF Export Script

Now, let’s assemble the pieces into a complete workflow. You can reuse this template for many different projects.

from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer

def export_pdf(filename):
    doc = SimpleDocTemplate(filename, pagesize=A4)
    elements = []

    # Add title and content
    elements.append(Paragraph("BUSINESS PERFORMANCE REPORT", title_style))
    elements.append(Spacer(1, 15))
    
    body_style = ParagraphStyle('Body', fontName='Arial', fontSize=12)
    elements.append(Paragraph("Summary data as of the end of the month:", body_style))
    elements.append(Spacer(1, 20))

    # Insert the created table and chart
    elements.append(table)
    elements.append(Spacer(1, 30))
    elements.append(create_chart())

    doc.build(elements)
    print(f"Success! File saved at: {filename}")

if __name__ == "__main__":
    export_pdf("Monthly_Report.pdf")

Real-world Implementation Tips

To ensure the system runs stably in a production environment, keep these 3 points in mind:

  • File Management: Always use try...except when writing files. If the PDF file is open in another application, the script will crash immediately.
  • Image Optimization: If the report includes logos or avatars, resize them to the actual display size. This can reduce the file size from several MBs down to a few dozen KBs.
  • Full Automation: Combine this script with a scheduling tool (like a Cron job or APScheduler). The system can automatically send reports at 8 AM every Monday without any manual intervention.

Mastering ReportLab frees you from tedious, repetitive tasks. Although the initial setup takes some time, the result is a professional, accurate, and fast workflow.

Share: