使用Python操作Word模板填充内容。根据占位符来填充word模板并导出 电脑版发表于:2025/6/5 11:30 [TOC] ### 方法一:使用python-docx来操作 #### 安装python-docx库 ``` pip install python-docx ``` #### 创建Word模板,在需要填充的位置使用占位符,例如: ``` 尊敬的{{name}}: 您的订单{{order_id}}已于{{date}}发货。 ``` #### 示例代码 ``` from docx import Document def fill_word_template(template_path, output_path, context): """ 填充Word模板 :param template_path: 模板文件路径 :param output_path: 输出文件路径 :param context: 包含替换内容的字典,如{'name': '张三', 'order_id': '12345'} """ # 加载模板文件 doc = Document(template_path) # 遍历文档中的所有段落 for paragraph in doc.paragraphs: # 替换段落中的占位符 for key, value in context.items(): if f'{{{{{key}}}}}' in paragraph.text: paragraph.text = paragraph.text.replace(f'{{{{{key}}}}}', str(value)) # 遍历文档中的所有表格 for table in doc.tables: for row in table.rows: for cell in row.cells: for key, value in context.items(): if f'{{{{{key}}}}}' in cell.text: cell.text = cell.text.replace(f'{{{{{key}}}}}', str(value)) # 保存填充后的文档 doc.save(output_path) # 使用示例 if __name__ == '__main__': # 定义替换内容 context = { 'name': '张三', 'order_id': 'ORD20230001', 'date': '2023-05-20' } # 填充模板 fill_word_template('template.docx', 'output.docx', context) ``` #### 加了一点路径处理的 ``` from docx import Document import os def fill_word_template(template_path, output_path, context): """ 填充Word模板 :param template_path: 模板文件路径 :param output_path: 输出文件路径 :param context: 包含替换内容的字典,如{'name': '张三', 'order_id': '12345'} """ # 加载模板文件 doc = Document(template_path) # 遍历文档中的所有段落 for paragraph in doc.paragraphs: # 替换段落中的占位符 for key, value in context.items(): if f'{{{{{key}}}}}' in paragraph.text: paragraph.text = paragraph.text.replace(f'{{{{{key}}}}}', str(value)) # 遍历文档中的所有表格 for table in doc.tables: for row in table.rows: for cell in row.cells: for key, value in context.items(): if f'{{{{{key}}}}}' in cell.text: cell.text = cell.text.replace(f'{{{{{key}}}}}', str(value)) # 保存填充后的文档 doc.save(output_path) # 使用示例 if __name__ == '__main__': knowledge_objectives = """ 1. 学生能够准确阐述图标的概念,包括 “图标” 释意以及 “icon” 的含义。 2. 清晰了解图标的应用范围,明确其在不同场景下的需求,并且能够区分图标、标识与标志。 3. 深入理解图标设计的应用价值,为后续学习图标设计奠定理论基础。 """ # 定义替换内容 context = { 'name': '张三', 'order_id': 'ORD20230001', 'date': '2023-05-20', 'knowledge_objectives':knowledge_objectives, 'bibliography':"图标创意设计222" } # 确保这个路径是正确的 template_path = '222.docx' # 或者使用完整路径如 'C:/path/to/222.docx' # print("当前工作目录:", os.getcwd()) # 获取脚本所在目录 script_dir = os.path.dirname(os.path.abspath(__file__)) template_path = os.path.join(script_dir, 'template.docx') # print("模板完整路径:", template_path) # 构建输出目录(导出目录) outPutPath = os.path.join(script_dir, 'outputTemplate.docx') # 检查文件是否存在 if not os.path.exists(template_path): print(f"错误:文件 {template_path} 不存在") else: print("开始执行了!") # 填充模板 fill_word_template(template_path, outPutPath, context) ``` #### 缺点 不支持复杂的模板,某些情况下不支持格式保留,会影响字体与颜色等 ### 方法二:使用docxtpl库来操作,支持更复杂的模板处理与格式保留等 使用docxtpl库(基于python-docx,支持更强大的模板功能)。如果模板中有特殊格式(如加粗、斜体,不同颜色等),使用python-docx直接替换可能会丢失格式,此时docxtpl是更好的选择。 #### 安装docxtpl ``` pip install docxtpl ``` **如果是在Anaconda虚拟环境中安装,命令如下:** ``` conda install -c conda-forge docxtpl ``` #### 模板语法介绍 使用{{variable}}作为简单变量 使用{% for item in items %}...{% endfor %}进行循环 使用{% if condition %}...{% endif %}进行条件判断 ##### for语法 item中间可以自己设置样式 ``` {% for item in knowledge_objectives %} {{item}} {% endfor %} ``` 上面那种写法会换行,这样写就不会换行了 ``` {% for item in knowledge_objectives %} {{item}}{% endfor %} ``` **小技巧:循环体要占一行如果不想循环体引用的换行可以把循环体和标题放一行就不会换行了** ``` 一、知识目标:{% for item in knowledge_objectives %} 1. {{item}}{% endfor %} ``` ##### 双循环 有些代码没有换行可读性有点丑,但是实用,因为很多时候导出的时候不需要换行的 ``` {% for item in teaching_process.teaching_new_knowledge.teacher %} 1. {{item.title }}{% for details_item in item.list%} 1) {{ details_item}}{% endfor %}{% endfor %} ``` 这里的1.与1)是在word里边设置的格式,这个格式可以保留根据实际情况去设置格式即可 **第二种情况:** ``` {% for item in teaching_process.problem_introduction %}{% for details_item in item.teacher%}【教师】{{details_item. title}} {{details_item. details}}{%endfor %} 【学生】{{item. student}}{% endfor %} ``` #### 示例代码 ``` from docxtpl import DocxTemplate # 模板内容示例: # 尊敬的{{name}}: # # 您的订单信息: # {% for item in orders %} # 订单号: {{item.order_id}} # 商品: {{item.product}} # 数量: {{item.quantity}} # {% endfor %} context = { 'name': '李四', 'orders': [ {'order_id': '1001', 'product': '笔记本电脑', 'quantity': 1}, {'order_id': '1002', 'product': '鼠标', 'quantity': 2} ] } doc = DocxTemplate('template.docx') doc.render(context) doc.save('output.docx') ``` 这种方法更强大,可以处理循环、条件等复杂模板逻辑。 ### 把生成的填充之后的word直接生成文件流的形式,避免某些场景临时文件清理的开销,可以直接对接需要文件流的业务 #### 示例代码如下: ```python from io import BytesIO from docxtpl import DocxTemplate # 初始化模板 doc = DocxTemplate('template.docx') # 渲染上下文 context = { 'your_key': 'your_value' } # 替换为你的实际上下文 doc.render(context) # 创建内存文件流 file_stream = BytesIO() # 将渲染后的文档保存到内存流 doc.save(file_stream) # 关键步骤:将流指针重置到开头 file_stream.seek(0) # 现在 file_stream 就是包含渲染后文档的二进制流 # 你可以像操作普通文件对象一样使用它: file_content = file_stream.read() # 获取二进制内容 # 使用示例: # 1. 直接返回给Web框架(如Flask/Django) # return send_file(file_stream, as_attachment=True, download_name='output.docx') # 2. 传递给其他需要文件流的操作 # some_function_that_needs_file_stream(file_stream) # 注意:使用完毕后如果不再需要,可以关闭流 file_stream.close() ``` 关键点说明: 1. `BytesIO` 创建了一个内存中的二进制流对象,可以像文件对象一样操作 2. `doc.save(file_stream)` 会直接将渲染后的文档写入内存流 3. `seek(0)` 是必须的步骤,因为写入操作后流指针会停留在文件末尾,需要重置才能读取内容 4. 这种方式完全避免了物理文件的生成,适合需要直接处理文件流的场景(如Web响应、云存储上传等) 这种方法在需要保持无文件操作、或需要即时处理文档内容的场景下非常有用,比如: - Web应用中直接返回生成的文档 - 集成到需要文件流输入的工作流中 - 避免临时文件清理的开销 - 云函数等无持久化存储的环境 #### 结合在python django项目里边的一点应用片段 ``` # 1. 构建安全路径 template_name = "aicreate-plan-template.docx" template_dir = os.path.join(settings.MEDIA_ROOT, 'template_files') template_path = os.path.join(template_dir, template_name) # 2. 安全验证 if not template_path.startswith(template_dir): raise serializers.ValidationError("Invalid file name") if not os.path.exists(template_path): raise serializers.ValidationError("Template file not found") # 需要填充的内容(可以调用AI接口生成) context = { 'name': '张三', 'order_id': 'ORD20230001', 'date': '2023-05-20', 'knowledge_objectives':"666", 'bibliography':"图标创意设计222" } # 存储的临时模板(直接用流读取就不需要了,不然存储后还要删除文件就浪费工作了) # outPutPath = os.path.join(template_dir, 'outputTemplate.docx') # 填充AI生成的内容并且导出word doc = DocxTemplate(template_path) doc.render(context) # doc.save(outPutPath) # -------------- AI生成内容end --------------- # 创建内存文件流 memory_file = io.BytesIO() # 将渲染后的文档保存到内存流 doc.save(memory_file) # 关键步骤:将流指针重置到开头 memory_file.seek(0) # 现在 file_stream 就是包含渲染后文档的二进制流 # 你可以像操作普通文件对象一样使用它: file_content = memory_file.read() # 获取二进制内容 # 创建内存文件对象(持久化) # memory_file = io.BytesIO(file_content) memory_file.name = template_name # 设置文件名 memory_file.size = len(file_content) # 设置文件大小 # 创建DjangoFile对象 file = DjangoFile(memory_file) file.content_type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' # 计算MD5(使用内存数据) md5 = hashlib.md5(file_content).hexdigest() ```