【办公神器】python-docx-template完全指南:30分钟掌握高级Word模板自动化技术

【办公神器】python-docx-template完全指南:30分钟掌握高级Word模板自动化技术

1. python-docx-template基础概念

1.1 核心优势与特点

python-docx-template基于Jinja2模板引擎,为Word文档提供了强大的模板功能:

  • 所见即所得的模板设计:在Word中直接设计模板,保留所有格式
  • 强大的变量替换:支持文本、表格、图片等多种内容替换
  • 逻辑控制能力:条件语句、循环和复杂表达式
  • 与python-docx互补:结合两者优势实现更复杂功能
  • 保留Word原生格式:完美保留样式、页眉页脚和其他格式元素

1.2 与其他库的比较

功能 python-docx-template python-docx docxtpl
设计方式 模板驱动 代码驱动 模板驱动
学习曲线 简单 中等 中等
格式控制 直接在Word中完成 需要代码实现 直接在Word中完成
变量替换 需自行实现
条件逻辑 需自行实现
复杂结构 表格、列表、图片 完全可控 有限支持
适用场景 批量生成标准化文档 精确控制文档结构 简单文档生成

2. 环境配置与安装

2.1 安装步骤

# 安装核心库
pip install docxtpl

# 安装可选依赖(图像处理)
pip install pillow

# 安装可选依赖(Excel数据导入)
pip install pandas openpyxl

2.2 基本导入

from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm, Inches, Pt
import jinja2

3. 模板创建与基础应用

3.1 创建第一个Word模板

创建一个模板需要在Word文档中插入特定格式的变量:

  1. 打开Word创建新文档
  2. 在需要动态内容的位置插入变量,格式为{ { variable_name }}
  3. 根据需要设置文本格式、字体、对齐方式等
  4. 保存为.docx文件

模板示例:

尊敬的{
  
  { name }}:

  感谢您对{
  
  { company }}的关注与支持。我们已收到您于{
  
  { date }}提交的申请,
申请编号为{
  
  { application_id }}。我们将在{
  
  { response_days }}个工作日内给予回复。

如有疑问,请联系:{
  
  { contact_email }}

此致
敬礼

{
  
  { company }}
{
  
  { current_date }}

3.2 基本变量替换

from docxtpl import DocxTemplate
from datetime import datetime

# 加载模板
doc = DocxTemplate("template.docx")

# 准备上下文数据
context = {
   
   
    "name": "张三",
    "company": "ABC科技有限公司",
    "date": "2023年5月15日",
    "application_id": "APP-2023-0587",
    "response_days": 3,
    "contact_email": "[email protected]",
    "current_date": datetime.now().strftime("%Y年%m月%d日")
}

# 渲染文档
doc.render(context)

# 保存生成的文档
doc.save("generated_document.docx")

3.3 自定义Jinja2环境

from docxtpl import DocxTemplate
import jinja2

# 创建自定义过滤器
def currency_format(value):
    """将数字格式化为货币形式"""
    return "{:,.2f}".format(value)

def date_format(value, format="%Y年%m月%d日"):
    """格式化日期"""
    if isinstance(value, str):
        from datetime import datetime
        try:
            value = datetime.strptime(value, "%Y-%m-%d")
        except:
            return value
    return value.strftime(format)

# 设置自定义Jinja2环境
doc = DocxTemplate("invoice_template.docx")
jinja_env = jinja2.Environment(autoescape=True)
jinja_env.filters["currency"] = currency_format
jinja_env.filters["date_format"] = date_format

# 使用自定义环境
doc.render(context, jinja_env)
doc.save("generated_invoice.docx")

4. 高级变量与格式处理

4.1 富文本内容

from docxtpl import DocxTemplate, RichText

doc = DocxTemplate("richtext_template.docx")

# 创建富文本对象
rt = RichText()
rt.add('这是', style="Normal")
rt.add('红色', color='FF0000')
rt.add('和', style="Normal")
rt.add('粗体', bold=True)
rt.add('文本', style="Normal")
rt.add(',还有', style="Normal")
rt.add('斜体', italic=True)
rt.add('效果', style="Normal")

# 添加到上下文
context = {
   
   
    "rich_paragraph": rt
}

# 渲染文档
doc.render(context)
doc.save("richtext_output.docx")

4.2 图片插入

from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm

doc = DocxTemplate("image_template.docx")

# 准备图片
logo_image = InlineImage(doc, "company_logo.png", width=Mm(30))
signature = InlineImage(doc, "signature.png", width=Mm(50))

# 添加到上下文
context = {
   
   
    "company_name": "XYZ集团",
    "logo": logo_image,
    "manager_name": "李经理",
    "signature": signature
}

# 渲染文档
doc.render(context)
doc.save("with_images.docx")

4.3 表格处理

from docxtpl import DocxTemplate

doc = DocxTemplate("table_template.docx")

# 准备表格数据
products = [
    {
   
   "id": "P001", "name": "笔记本电脑", "price": 5999.00, "quantity": 2},
    {
   
   "id": "P002", "name": "无线鼠标", "price": 99.00, "quantity": 5},
    {
   
   "id": "P003", "name": "显示器", "price": 1299.00, "quantity": 1},
    {
   
   "id": "P004", "name": "机械键盘", "price": 399.00, "quantity": 3}
]

# 计算每个产品的小计和总计
for product in products:
    product["subtotal"] = product["price"] * product["quantity"]

total = sum(product["subtotal"] for product in products)

# 添加到上下文
context = {
   
   
    "customer": "王先生",
    "order_id": "ORD-2023-0892",
    "products": products,
    "total": total
}

# 渲染文档
doc.render(context)
doc.save("invoice_with_table.docx")

5. 逻辑控制与条件渲染

5.1 条件语句

在Word模板中使用条件语句:

尊敬的客户:

{% if membership == "premium" %}
  感谢您成为我们的高级会员,您将享受专属VIP服务。
{% elif membership == "standard" %}
  感谢您成为我们的标准会员,您将享受优质服务。
{% else %}
  感谢您的惠顾,希望您体验愉快。
{% endif %}

{% if balance > 1000 %}
  您当前账户余额充足,可以享受额外优惠。
{% endif %}

Python代码:

from docxtpl import DocxTemplate

doc = DocxTemplate("conditional_template.docx")

# 准备不同上下文数据
premium_context = {
   
   
    "customer_name": "张女士",
    "membership": "premium",
    "balance": 1500.00
}

standard_context = {
   
   
    "customer_name": "李先生",
    "membership": "standard",
    "balance": 800.00
}

# 渲染不同文档
doc.render(premium_context)
doc.save("premium_letter.docx")

# 重新加载模板(避免重复渲染)
doc = DocxTemplate("conditional_template.docx")
doc.render(standard_context)
doc.save("standard_letter.docx")

5.2 循环语句

在Word模板中使用循环:

交易记录摘要:

{% for transaction in transactions %}
  - {
  
  { transaction.date }} | {
  
  { transaction.type }} | {
  
  { transaction.amount }}元
{% endfor %}

{% if transactions|length > 5 %}
  以上仅显示最近5笔交易,查看完整记录请登录网站。
{% endif %}

Python代码:

from docxtpl import DocxTemplate
from datetime import datetime, timedelta

doc = DocxTemplate("loop_template.docx")

# 生成交易记录数据
transactions = []
today = datetime.now()
for i in range(7):
    tdate = today - timedelta(days=i)
    ttype = "存入" if i % 3 == 0 else "支出"
    tamount = 1000 + i * 100 if ttype == "存入" else 500 + i * 50
    
    transactions.append({
   
   
        "date": tdate.strftime("%Y-%m-%d"),
        "type": ttype,
        "amount": tamount
    })

# 添加到上下文
context = {
   
   
    "customer_name": "王女士",
    "account_id": "6225 **** **** 3752",
    "transactions": transactions
}

# 渲染文档
doc.render(context)
doc.save("transaction_report.docx")

5.3 高级表达式

在Word模板中使用计算和表达式:

账单摘要:
基础费用:{
  
  { base_price }}元
附加服务:{
  
  { additional_services }}元
优惠折扣:{
  
  { discount }}元
应付金额:{
  
  { base_price + additional_services - discount }}元

{% if (base_price + additional_services - discount) > 2000 %}
  您的消费已达到高级会员标准,可享受后续服务9折优惠。
{% endif %}

Python代码:

from docxtpl import DocxTemplate

doc = DocxTemplate("expression_template.docx")

# 准备上下文数据
context = {
   
   
    "customer_id": "CID-38291",
    "base_price": 1299.00,
    "additional_services": 899.00,
    "discount": 199.00
}

# 渲染文档
doc.render(context)
doc.save("bill_with_calculations.docx")

6. 复杂表格与动态生成

6.1 动态行表格

from docxtpl import DocxTemplate

doc = DocxTemplate("dynamic_table_template.docx")

# 动态生成学生成绩数据
students = []
for i in range(1, 11):
    math_score = 70 + (i % 3) * 10
    english_score = 75 + (i % 4) * 8
    science_score = 80 + (i % 5) * 5
    
    total = math_score + english_score + science_score
    average = total / 3
    
    students.append({
   
   
        "id": f"S{
     
     2023100 + i}",
        "name": f"学生{
     
     i}",
        "math": math_score,
        "english": english_score,
        "science": science_score,
        "total": total,
        "average": round(average, 1),
        "pass": "通过" if average >= 60 else "未通过"
    })

# 添加到上下文
context = {
   
   
    "class_name": "高一(3)班",
    "term": "2023年春季学期",
    "exam_date": "2023年6月15日",
    "students": students
}

# 渲染文档
doc.render(context)
doc.save("class_report_card.docx")

6.2 嵌套表格

from docxtpl import DocxTemplate

doc = DocxTemplate("nested_table_template.docx")

# 准备部门和员工数据
departments = [
    {
   
   
        "name": "研发部",
        "manager": "张工",
        "employees": [
            {
   
   "id": "E001", "name": "李明", "position": "高级工程师", "salary": 18000},
            {
   
   "id": "E002", "name": "王芳", "position": "工程师", "salary": 15000},
            {
   
   "id": "E003", "name": "赵强", "position": "工程师", "salary": 14000}
        ]
    },
    {
   
   
        "name": "市场部",
        "manager": "刘总",
        "employees": [
            {
   
   "id": "E010", "name": "张丽", "position": "市场经理", "salary": 16000},
            {
   
   "id": "E011", "name": "周红", "position": "销售主管", "salary": 13000}
        ]
    }
]

# 计算部门统计信息
for dept in departments:
    dept["employee_count"] = len(dept["employees"])
    dept["avg_salary"] = sum(e["salary"] for e in dept["employees"]) / dept["employee_count"]

# 添加到上下文
context = {
   
   
    "company_name": "ABC科技有限公司",
    "report_date": "2023年7月1日",
    "departments": departments
}

# 渲染文档
doc.render(context)
doc.save("company_structure_report.docx")

6.3 表格样式控制

from docxtpl import DocxTemplate, RichText

doc = DocxTemplate("styled_table_template.docx")

# 准备数据
sales_data = [
    {
   
   "region": "东区", "q1": 1250000, "q2": 1380000, "q3": 1420000, "q4": 1600000},
    {
   
   "region": "西区", "q1": 980000, "q2": 1040000, "q3": 1100000, "q4": 1250000},
    {
   
   "region": "南区", "q1": 1100000, "q2": 1150000, "q3": 1300000, "q4": 1450000},
    {
   
   "region": "北区", "q1": 850000, "q2": 920000, "q3": 980000, "q4": 1050000}
]

# 计算同比增长并添加样式
for region in sales_data:
    # 计算年度总销售额
    region["total"] = region["q1"] + region["q2"] + region["q3"] + region["q4"]
    
    # 创建富文本对象并添加颜色(根据销售额)
    for quarter in ["q1", "q2", "q3", "q4", "total"]:
        value = region[quarter]
        rt = RichText()
        
        if quarter == "total":
            # 总销售额显示为粗体
            rt.add(f"{
     
     value:,}", bold=True)
        else:
            # 季度销售额根据数值显示不同颜色
            if value >= 1300000:
                rt.add(f"{
     
     value:,}", color="007700")  # 绿色(好)
            elif value >= 1000000:
                rt.add(f"{
     
     value:,}", color="000000")  # 黑色(一般)
            else:
                rt.add(f"{
     
     value:,}", color="CC0000")  # 红色(差)
        
        region[f"{
     
     quarter}_styled"] = rt

# 添加到上下文
context = {
   
   
    "year": "2023",
    "report_title": "区域销售业绩分析",
    "sales_data": sales_data
}

# 渲染文档
doc.render(context)
doc.save("sales_performance_report.docx")

7. 实用场景案例

7.1 客户合同生成系统

from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm
from datetime import datetime
import os
import pandas as pd

def generate_contract(customer_data, template_path="contract_template.docx", output_dir="generated_contracts"):
    """根据客户数据生成合同"""
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)
    
    # 加载合同模板
    doc = DocxTemplate(template_path)
    
    # 准备上下文数据
    context = customer_data.copy()
    
    # 添加日期格式化
    context["contract_date"] = datetime.now().strftime("%Y年%m月%d日")
    context["start_date"] = datetime.strptime(context["start_date"], "%Y-%m-%d").strftime("%Y年%m月%d日")
    context["end_date"] = datetime.strptime(context["end_date"], "%Y-%m-%d").strftime("%Y年%m月%d日")
    
    # 计算合同金额中文大写
    from num2chinese import num2chinese
    context["amount_chinese"] = num2chinese(context["amount"])
    
    # 添加签名图片
    if "signature_path" in context and os.path.exists(context["signature_path"]):
        context["signature"] = InlineImage(doc, context["signature_path"], width=Mm(30))
    
    # 添加公司印章图片
    if "stamp_path" in context and os.path.exists(context["stamp_path"]):
        context["company_stamp"] = InlineImage(doc, context["stamp_path"], width=Mm(40))
    
    # 渲染文档
    doc.render(context)
    
    # 构建输出文件名
    output_filename = f"合同_{
     
     context['customer_name']}_{
     
     context['contract_id']}.docx"
    output_path = os.path.join(output_dir, output_filename)
    
    # 保存生成的合同
    doc.save(output_path)
    
    return output_path

# 从Excel导入客户数据
def generate_contracts_from_excel(excel_path, template_path, output_dir):
    """从Excel批量生成合同"""
    # 读取Excel数据
    df = pd.read_excel(excel_path)
    
    # 转换为字典列表
    customers = df.to_dict(orient='records')
    
    # 生成的合同路径列表
    generated_files = []
    
    # 批量生成合同
    for customer in customers:
        output_path = generate_contract(customer, template_path, output_dir)
        generated_files.append(output_path)
        print(f"已生成合同: {
     
     output_path}")
    
    return generated_files

# 使用示例
generated_contracts = generate_contracts_from_excel(
    "customer_data.xlsx", 
    "contract_template.docx", 
    "output_contracts"
)
print(f"成功生成 {
     
     len(generated_contracts)} 份合同文档")

7.2 定制化证书生成

from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm
import os
import pandas as pd
from datetime import datetime
import qrcode
from PIL import Image

def generate_certificate(participant_data, template_path="certificate_template.docx", 
                        output_dir="generated_certificates", add_qr=True):
    """生成参与者证书"""
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)
    
    # 加载证书模板
    doc = DocxTemplate(template_path)
    
    # 准备上下文数据
    context = participant_data.copy()
    
    # 格式化日期
    issue_date = datetime.now().strftime("%Y年%m月%d日")
    context["issue_date"] = issue_date
    
    # 生成证书验证二维码
    if add_qr:
        qr_data = f"证书ID: {
     
     context['certificate_id']}\n"
        qr_data += f"姓名: {
     
     context['name']}\n"
        qr_data += f"课程: {
     
     context['course_name']}\n"
        qr_data += f"日期: {
     
     issue_date}\n"
        qr_data += f"验证网址: https://example.com/verify/{
     
     context['certificate_id']}"
        
        # 生成二维码图片
        qr = qrcode.QRCode(
            version=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫比乌斯@卷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值