Generating Custom Excel Reports with Python: A Comprehensive Guide
When it comes to automating report generation and enhancing the readability of Excel files, Python provides a powerful set of libraries, including OpenPyXL and Pillow. In this post, we will dive into a Python script designed for generating custom Excel reports by populating templates with dynamic data, including text, images, and conditional formatting. This solution is particularly useful for businesses or developers who frequently work with Excel files and need a programmatic way to customize them.
What Does the Script Do?
This Python script is designed to:
- Load an Excel template and populate it with dynamic data.
- Customize content such as text placeholders, images, and checkboxes.
- Hide or group rows conditionally based on specific rules.
- Handle image resizing and alignment, including centering within specific cells.
- Export the customized workbook as a new Excel file with a timestamped filename.
Let’s break down the script and demonstrate its usage.
The Complete Code
Below is the complete script for generating custom Excel reports:
from openpyxl import load_workbook, Workbook
from datetime import datetime
from openpyxl.drawing.image import Image
import re
from openpyxl.drawing.spreadsheet_drawing import AbsoluteAnchor
from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
from openpyxl.utils.units import pixels_to_EMU
from openpyxl.utils import get_column_letter, column_index_from_string
from django.conf import settings
from PIL import Image as PILImage
import os
def set_image_with_offset(sheet, img, cell_coordinate, offset_x=0, offset_y=0):
col_letter = ''.join(filter(str.isalpha, cell_coordinate)) # Extract column letter
row_number = int(''.join(filter(str.isdigit, cell_coordinate))) # Extract row number
col_idx = column_index_from_string(col_letter) - 1
row_idx = row_number - 1
col_width = sheet.column_dimensions[col_letter].width or 10 # Default column width
row_height = sheet.row_dimensions[row_number].height or 15 # Default row height
col_pixels = col_width * 7.5 # Approximation: ~7.5 pixels per width unit
row_pixels = row_height * 0.75 # Approximation: ~0.75 pixels per height unit
cell_x = col_idx * col_pixels
cell_y = row_idx * row_pixels
final_x = cell_x + offset_x
final_y = cell_y + offset_y
pos = XDRPoint2D(pixels_to_EMU(final_x), pixels_to_EMU(final_y))
size = XDRPositiveSize2D(pixels_to_EMU(img.width), pixels_to_EMU(img.height))
img.anchor = AbsoluteAnchor(pos=pos, ext=size)
sheet.add_image(img)
def center_image_in_cell(sheet, img, cell_coordinate):
col_letter = ''.join(filter(str.isalpha, cell_coordinate))
row_number = int(''.join(filter(str.isdigit, cell_coordinate)))
col_width = sheet.column_dimensions[col_letter].width or 10
row_height = sheet.row_dimensions[row_number].height or 15
col_pixels = col_width * 7.5
row_pixels = row_height * 0.75
img_width, img_height = img.width, img.height
offset_x = int((col_pixels - img_width) / 2 * pixels_to_EMU(1))
offset_y = int((row_pixels - img_height) / 2 * pixels_to_EMU(1))
img.anchor = AbsoluteAnchor(
pos=XDRPoint2D(pixels_to_EMU(offset_x), pixels_to_EMU(offset_y)),
ext=XDRPositiveSize2D(pixels_to_EMU(img_width), pixels_to_EMU(img_height)),
)
sheet.add_image(img)
def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
checked_image_path = f"{settings.BASE_DIR}/report/checkbox_checked.jpg"
unchecked_image_path = f"{settings.BASE_DIR}/report/checkbox_unchecked.jpg"
workbook = load_workbook(template_file)
for sheet_name in workbook.sheetnames:
if sheet_name not in selected_sheets:
del workbook[sheet_name]
for sheet_name in selected_sheets:
sheet = workbook[sheet_name]
for row in sheet.iter_rows():
for cell in row:
if cell.value and isinstance(cell.value, str) and cell.value.startswith("<") and cell.value.endswith(">"):
placeholder = cell.value.strip("<>")
value = data.get(placeholder)
if isinstance(value, str):
cell.value = value
elif isinstance(value, bool):
img = Image(checked_image_path if value else unchecked_image_path)
center_image_in_cell(sheet, img, cell.coordinate)
cell.value = None
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_path = f"{prefix_filename}_{timestamp}.xlsx"
workbook.save(output_path)
return output_path
if __name__ == "__main__":
data = {
"customer": "Alice Johnson",
"inspect_date": "2025-02-01",
"lot_no": "ABC12345",
"staff_name": "Inspector Team",
"size": "Medium",
"pcs": "25 pcs",
"hardness.d1_act": "12.5",
"hardness.acc": True,
"hardness.spe_acc": False,
"dimension_app.d1_act": "45.8",
"dimension_app.acc": True,
"dimension_app.spe_acc": True,
}
output_file = gen_xlsx(
template_file="./inspection_template.xlsx",
selected_sheets=["hardness", "dimensions"],
prefix_filename="./reports/inspection_report",
data=data,
)
print(f"Generated file: {output_file}")
Demo Data Explanation
In this example, we used a new set of data to demonstrate how the script works:
- Customer Information: Contains general details like the customer’s name, inspection date, and lot number.
- Measurements and Results: Dynamic data for specific cells, including numerical values, checkboxes (
TrueorFalse), and placeholder text. - Checkbox Logic: Boolean values like
"hardness.acc": Trueautomatically insert a checked or unchecked checkbox image into the Excel sheet.
How to Use the Script
- Prepare an Excel template with placeholders like
<customer>,<inspect_date>, etc. - Define the data dictionary with keys matching the placeholders.
- Call the
gen_xlsxfunction with the template path, selected sheet names, prefix for the output file, and the data dictionary. - Run the script, and the customized Excel file will be generated.
Conclusion
This script is a versatile tool for automating Excel report generation, saving time, and reducing errors. It can be tailored for various applications, from inspection reports to financial summaries. Feel free to modify the script to suit your specific needs, and enjoy the power of Python for Excel automation! 🚀
Get in Touch with us
Related Posts
- ERP项目为何失败(以及如何让你的项目成功)
- Why ERP Projects Fail (And How to Make Yours Succeed)
- Payment API幂等性设计:用Stripe、支付宝、微信支付和2C2P防止重复扣款
- Idempotency in Payment APIs: Prevent Double Charges with Stripe, Omise, and 2C2P
- Agentic AI in SOC Workflows: Beyond Playbooks, Into Autonomous Defense (2026 Guide)
- 从零构建SOC:Wazuh + IRIS-web 真实项目实战报告
- Building a SOC from Scratch: A Real-World Wazuh + IRIS-web Field Report
- 中国品牌出海东南亚:支付、物流与ERP全链路集成技术方案
- 再生资源工厂管理系统:中国回收企业如何在不知不觉中蒙受损失
- 如何将电商平台与ERP系统打通:实战指南(2026年版)
- AI 编程助手到底在用哪些工具?(Claude Code、Codex CLI、Aider 深度解析)
- 使用 Wazuh + 开源工具构建轻量级 SOC:实战指南(2026年版)
- 能源管理软件的ROI:企业电费真的能降低15–40%吗?
- The ROI of Smart Energy: How Software Is Cutting Costs for Forward-Thinking Businesses
- How to Build a Lightweight SOC Using Wazuh + Open Source
- How to Connect Your Ecommerce Store to Your ERP: A Practical Guide (2026)
- What Tools Do AI Coding Assistants Actually Use? (Claude Code, Codex CLI, Aider)
- How to Improve Fuel Economy: The Physics of High Load, Low RPM Driving
- 泰国榴莲仓储管理系统 — 批次追溯、冷链监控、GMP合规、ERP对接一体化
- Durian & Fruit Depot Management Software — WMS, ERP Integration & Export Automation













