使用 python-docx-template 自动生成新能源技术报告
在风电、光伏项目里,我们经常需要输出一份结构相对固定、但数据每次都不同的 Word 报告: 比如“规划容量与发电量计算”“资源评估”“经济性测算”等。
python-docx-template 的作用,就是把这件事变成一条流水线:
Word 模板(.docx) + 数据(YAML / Excel / JSON 等) → 自动生成完整报告
下面一步步来,从最常用、最关键的几个动作讲起。
安装与最小可用示例
先安装:
pip install docxtpl
最小示例:把“项目名称”写进 Word 模板。
from docxtpl import DocxTemplate
doc = DocxTemplate("templates/report_template.docx")
context = {
"项目名称": "某地分布式光伏项目",
"规划容量": "50 MWp",
}
doc.render(context)
doc.save("output/光伏项目自动报告示例.docx")
Word 模板里对应的占位符写成:
本报告针对 {{ 项目名称 }} ,规划容量约为 {{ 规划容量 }}。
到这一步,你已经完成了最基本的“用 Python 往 Word 里灌数据”。
设计 Word 模板
基本变量写法
在 Word 中插入变量占位符时,遵守几个简单规则:
- 必须用花括号包起来:
{{ 变量名 }} - 指标中间不要有冒号,不要有空格:❌
{{ 屋顶面积 m2 }} - 指标名称不能以数字开头:❌
{{ 25年发电量 }} - 可以用中文或字母开头,后面跟数字或下划线:✅
{{ 屋顶面积_m2 }}、{{ 年均满发小时数 }}
推荐风格:
{{ 项目名称 }}
{{ 屋顶面积_m2 }}
{{ 规划容量_MWp }}
{{ 年均发电量_万千瓦时 }}
在表格中迭代“逐月发电量 / 辐射量”
典型需求:在报告中列一个“斜面辐射量逐月统计表”或“25 年发电量衰减表”。
在 Word 里建好表头,然后在数据行那一行写模板语法:
{% for row in 斜面辐射量_逐月 %}
{{ row.月份 }} {{ row.水平总辐射量 }} {{ row.散射辐射量 }} {{ row.直接辐射量 }}
{% endfor %}
对应的 Python 数据结构(注意只给关键字段):
context = {
"斜面辐射量_逐月": [
{"月份": 1, "水平总辐射量": 73, "散射辐射量": 28, "直接辐射量": 108},
{"月份": 2, "水平总辐射量": 89, "散射辐射量": 39, "直接辐射量": 103},
# ... 按月追加即可
],
}
模板里只需要记住一句话:
“我在 Word 里写 for row in xxx,Python 这边就给一个列表 xxx。”
从 YAML / Excel 读取数据并组装 context
实际项目里,数据往往已经在 YAML 或 Excel 里算好了。
我们要做的,就是把它们读出来,整理成 context 字典。
从 YAML 读取基础信息
假设有一个 YAML 文件里保存了项目的基础信息和资源数据,可以这样读:
import yaml
from pathlib import Path
def load_yaml_data(path: str) -> dict:
with open(path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
raw = load_yaml_data("data/project.yaml")
context = {
# 基础信息
"项目名称": raw.get("项目名称", "某风光项目"),
"公司名称": raw.get("公司名称", "某能源科技有限公司"),
"咨询时间": raw.get("咨询时间", ""),
"项目位置": raw.get("项目位置", ""),
# 资源指标
"总辐射量kWh": raw.get("总辐射量kWh", ""),
"资源等级": raw.get("资源等级", ""),
# 容量与发电量
"屋顶面积_m2": raw.get("屋顶面积_m2", ""),
"规划容量": raw.get("规划容量", ""),
"年均发电量": raw.get("年均发电量", ""),
}
你不需要一次性把所有键都塞进去,只挑报告真正用到的字段就好。
从 Excel 中读取“计算结果表”
容量、发电量、多年衰减这些,通常会先在 Excel 里算一遍,再导入报告。
用 pandas 读一个简单的“发电量计算”工作表,转换为模板可用的数据
(如果表的结构本身很复杂,使用 openpyxl 也是一个不错的选择):
import pandas as pd
def load_generation_sheet(path: str) -> list[dict]:
df = pd.read_excel(path, sheet_name="发电量计算")
# 只保留关键列,改一下列名方便模板使用
df = df[["年份", "效率", "实际发电量", "等效利用小时数"]]
return df.to_dict(orient="records")
generation_rows = load_generation_sheet("data/规划容量与发电量计算.xlsx")
context["发电量计算列表"] = generation_rows
Word 模板中的表格这样写:
{% for row in 发电量计算列表 %}
{{ row.年份 }} 年 {{ row.效率 }} {{ row.实际发电量 }} 万千瓦时 {{ row.等效利用小时数 }} 小时
{% endfor %}
整体流程
把前面几步串起来,就是一个完整的自动报告流程。
from docxtpl import DocxTemplate
def build_context():
raw = load_yaml_data("data/project.yaml")
generation_rows = load_generation_sheet("data/规划容量与发电量计算.xlsx")
return {
# 基础信息
"项目名称": raw.get("项目名称", "某风电/光伏项目"),
"公司名称": raw.get("公司名称", "某能源科技公司"),
"咨询时间": raw.get("咨询时间", ""),
# 资源与容量
"总辐射量kWh": raw.get("总辐射量kWh", ""),
"规划容量": raw.get("规划容量", ""),
"年均发电量": raw.get("年均发电量", ""),
# 列表类数据
"发电量计算列表": generation_rows,
"斜面辐射量_逐月": raw.get("斜面辐射量", {}).get("逐月", []),
}
def render_report():
doc = DocxTemplate("templates/规划容量与发电量计算模板.docx")
context = build_context()
doc.render(context)
doc.save("output/自动生成的风光项目报告.docx")
if __name__ == "__main__":
render_report()
实际使用中,你只需要换掉:
- 模板路径
- 数据文件路径
- 输出文件路径
就能在不同项目间复用同一套代码。
条件判断
有些章节是“可选”的,比如:
- 是否写“气象要素详细分析”
- 是否展示“多场景敏感性分析”
可以在模板里用 if 控制段落是否出现。
Word 模板中
{% if 气象要素 %}
本节简要介绍项目所在区域的气象特征:
{{ 气象要素 }}
{% endif %}
Python 里控制
context["气象要素"] = raw.get("气象要素") # 没有就为 None,块会自动不显示
这比“先在 Python 拼接一大段字符串”要轻松很多,也更贴近写文档的思路。
插入发电量曲线 / 辐射分布图
python-docx-template 支持把图片当成变量塞进去,很适合插入:
- 年发电量变化曲线
- 月总辐射量柱状图
- 项目区位图/用地示意图
模板中占位符
{{ 年发电量曲线图 }}
Python 里填充图片
from docxtpl import InlineImage, DocxTemplate
from docx.shared import Mm
doc = DocxTemplate("templates/report_template.docx")
context = {
# 其他变量...
"年发电量曲线图": InlineImage(
doc,
"assets/project/images/generation_curve.png",
height=Mm(70),
)
}
doc.render(context)
doc.save("output/带图片的报告示例.docx")
可以按“项目 ID / 项目简称”组织图片路径,报告生成时只需要换一组路径即可。
数据缺失时的兜底策略
风电 / 光伏项目数据不一定一次性齐全,有些字段缺了,模板里直接空白会很尴尬。 常用做法是设置“缺失文本”,让读者一眼就知道数据没填上,而不是以为漏写了。
简单版本可以在组装 context 时做:
def get_or_missing(raw: dict, key: str) -> str:
return raw.get(key) or f"%数据缺失:{key}%"
context = {
"项目名称": get_or_missing(raw, "项目名称"),
"规划容量": get_or_missing(raw, "规划容量"),
"总辐射量kWh": get_or_missing(raw, "总辐射量kWh"),
}
在 Word 里就会显示类似:
规划容量:%数据缺失:规划容量%
方便你在人工校核时快速定位问题。
常见小坑与检查清单
最后,给自己留一份“踩坑清单”,免得每次都忘:
-
变量命名
- 中间不要有空格、冒号
- 不要以数字开头
- 中文 / 英文都可以,用下划线分隔词更清晰
-
Word 模板里的空格
- 占位符里不要多打空格,建议写成
{{变量名}}或{{ 变量名 }},整体保持一致。
- 占位符里不要多打空格,建议写成
-
列表字段为空
- 如果类似
发电量计算列表是空列表,循环不会输出任何行,表格会只剩表头——这是预期行为。 - 真正要避免的是:字段是
None或漏掉,这时模板容易报错,建议统一给空列表。
- 如果类似
-
模板调试方法
- 可以先在模板里只放几个关键变量,跑通一版,确认路径和变量名都没问题,再一点一点把表格、图片、条件块加回来。