心不死则道不生,欲不灭则道不存
排名
1
文章
877
粉丝
112
评论
163
net core webapi post传递参数
庸人 : 确实坑哈,我也是下班好了好几次,发现后台传递对象是可以的,但...
百度编辑器自定义模板
庸人 : 我建议换个编辑器,因为现在百度富文本已经停止维护了,用tinymec...
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

使用Python操作Word模板填充内容。根据占位符来填充word模板并导出

296人阅读 2025/6/5 11:30 总访问:5554674 评论:0 收藏:0 手机
分类: Python

方法一:使用python-docx来操作

安装python-docx库

  1. pip install python-docx

创建Word模板,在需要填充的位置使用占位符,例如:

  1. 尊敬的{{name}}:
  2. 您的订单{{order_id}}已于{{date}}发货。

示例代码

  1. from docx import Document
  2. def fill_word_template(template_path, output_path, context):
  3. """
  4. 填充Word模板
  5. :param template_path: 模板文件路径
  6. :param output_path: 输出文件路径
  7. :param context: 包含替换内容的字典,如{'name': '张三', 'order_id': '12345'}
  8. """
  9. # 加载模板文件
  10. doc = Document(template_path)
  11. # 遍历文档中的所有段落
  12. for paragraph in doc.paragraphs:
  13. # 替换段落中的占位符
  14. for key, value in context.items():
  15. if f'{{{{{key}}}}}' in paragraph.text:
  16. paragraph.text = paragraph.text.replace(f'{{{{{key}}}}}', str(value))
  17. # 遍历文档中的所有表格
  18. for table in doc.tables:
  19. for row in table.rows:
  20. for cell in row.cells:
  21. for key, value in context.items():
  22. if f'{{{{{key}}}}}' in cell.text:
  23. cell.text = cell.text.replace(f'{{{{{key}}}}}', str(value))
  24. # 保存填充后的文档
  25. doc.save(output_path)
  26. # 使用示例
  27. if __name__ == '__main__':
  28. # 定义替换内容
  29. context = {
  30. 'name': '张三',
  31. 'order_id': 'ORD20230001',
  32. 'date': '2023-05-20'
  33. }
  34. # 填充模板
  35. fill_word_template('template.docx', 'output.docx', context)

加了一点路径处理的

  1. from docx import Document
  2. import os
  3. def fill_word_template(template_path, output_path, context):
  4. """
  5. 填充Word模板
  6. :param template_path: 模板文件路径
  7. :param output_path: 输出文件路径
  8. :param context: 包含替换内容的字典,如{'name': '张三', 'order_id': '12345'}
  9. """
  10. # 加载模板文件
  11. doc = Document(template_path)
  12. # 遍历文档中的所有段落
  13. for paragraph in doc.paragraphs:
  14. # 替换段落中的占位符
  15. for key, value in context.items():
  16. if f'{{{{{key}}}}}' in paragraph.text:
  17. paragraph.text = paragraph.text.replace(f'{{{{{key}}}}}', str(value))
  18. # 遍历文档中的所有表格
  19. for table in doc.tables:
  20. for row in table.rows:
  21. for cell in row.cells:
  22. for key, value in context.items():
  23. if f'{{{{{key}}}}}' in cell.text:
  24. cell.text = cell.text.replace(f'{{{{{key}}}}}', str(value))
  25. # 保存填充后的文档
  26. doc.save(output_path)
  27. # 使用示例
  28. if __name__ == '__main__':
  29. knowledge_objectives = """
  30. 1. 学生能够准确阐述图标的概念,包括 “图标” 释意以及 “icon” 的含义。
  31. 2. 清晰了解图标的应用范围,明确其在不同场景下的需求,并且能够区分图标、标识与标志。
  32. 3. 深入理解图标设计的应用价值,为后续学习图标设计奠定理论基础。
  33. """
  34. # 定义替换内容
  35. context = {
  36. 'name': '张三',
  37. 'order_id': 'ORD20230001',
  38. 'date': '2023-05-20',
  39. 'knowledge_objectives':knowledge_objectives,
  40. 'bibliography':"图标创意设计222"
  41. }
  42. # 确保这个路径是正确的
  43. template_path = '222.docx' # 或者使用完整路径如 'C:/path/to/222.docx'
  44. # print("当前工作目录:", os.getcwd())
  45. # 获取脚本所在目录
  46. script_dir = os.path.dirname(os.path.abspath(__file__))
  47. template_path = os.path.join(script_dir, 'template.docx')
  48. # print("模板完整路径:", template_path)
  49. # 构建输出目录(导出目录)
  50. outPutPath = os.path.join(script_dir, 'outputTemplate.docx')
  51. # 检查文件是否存在
  52. if not os.path.exists(template_path):
  53. print(f"错误:文件 {template_path} 不存在")
  54. else:
  55. print("开始执行了!")
  56. # 填充模板
  57. fill_word_template(template_path, outPutPath, context)

缺点

不支持复杂的模板,某些情况下不支持格式保留,会影响字体与颜色等

方法二:使用docxtpl库来操作,支持更复杂的模板处理与格式保留等

使用docxtpl库(基于python-docx,支持更强大的模板功能)。如果模板中有特殊格式(如加粗、斜体,不同颜色等),使用python-docx直接替换可能会丢失格式,此时docxtpl是更好的选择。

安装docxtpl

  1. pip install docxtpl

如果是在Anaconda虚拟环境中安装,命令如下:

  1. conda install -c conda-forge docxtpl

模板语法介绍

使用{{variable}}作为简单变量
使用{% for item in items %}…{% endfor %}进行循环
使用{% if condition %}…{% endif %}进行条件判断

for语法

item中间可以自己设置样式

  1. {% for item in knowledge_objectives %}
  2. {{item}}
  3. {% endfor %}

上面那种写法会换行,这样写就不会换行了

  1. {% for item in knowledge_objectives %}
  2. {{item}}{% endfor %}

小技巧:循环体要占一行如果不想循环体引用的换行可以把循环体和标题放一行就不会换行了

  1. 一、知识目标:{% for item in knowledge_objectives %}
  2. 1. {{item}}{% endfor %}
双循环

有些代码没有换行可读性有点丑,但是实用,因为很多时候导出的时候不需要换行的

  1. {% for item in teaching_process.teaching_new_knowledge.teacher %}
  2. 1. {{item.title }}{% for details_item in item.list%}
  3. 1) {{ details_item}}{% endfor %}{% endfor %}

这里的1.与1)是在word里边设置的格式,这个格式可以保留根据实际情况去设置格式即可

第二种情况:

  1. {% for item in teaching_process.problem_introduction %}{% for details_item in item.teacher%}【教师】{{details_item. title}}
  2. {{details_item. details}}{%endfor %}
  3. 【学生】{{item. student}}{% endfor %}

示例代码

  1. from docxtpl import DocxTemplate
  2. # 模板内容示例:
  3. # 尊敬的{{name}}:
  4. #
  5. # 您的订单信息:
  6. # {% for item in orders %}
  7. # 订单号: {{item.order_id}}
  8. # 商品: {{item.product}}
  9. # 数量: {{item.quantity}}
  10. # {% endfor %}
  11. context = {
  12. 'name': '李四',
  13. 'orders': [
  14. {'order_id': '1001', 'product': '笔记本电脑', 'quantity': 1},
  15. {'order_id': '1002', 'product': '鼠标', 'quantity': 2}
  16. ]
  17. }
  18. doc = DocxTemplate('template.docx')
  19. doc.render(context)
  20. doc.save('output.docx')

这种方法更强大,可以处理循环、条件等复杂模板逻辑。

把生成的填充之后的word直接生成文件流的形式,避免某些场景临时文件清理的开销,可以直接对接需要文件流的业务

示例代码如下:

  1. from io import BytesIO
  2. from docxtpl import DocxTemplate
  3. # 初始化模板
  4. doc = DocxTemplate('template.docx')
  5. # 渲染上下文
  6. context = { 'your_key': 'your_value' } # 替换为你的实际上下文
  7. doc.render(context)
  8. # 创建内存文件流
  9. file_stream = BytesIO()
  10. # 将渲染后的文档保存到内存流
  11. doc.save(file_stream)
  12. # 关键步骤:将流指针重置到开头
  13. file_stream.seek(0)
  14. # 现在 file_stream 就是包含渲染后文档的二进制流
  15. # 你可以像操作普通文件对象一样使用它:
  16. file_content = file_stream.read() # 获取二进制内容
  17. # 使用示例:
  18. # 1. 直接返回给Web框架(如Flask/Django)
  19. # return send_file(file_stream, as_attachment=True, download_name='output.docx')
  20. # 2. 传递给其他需要文件流的操作
  21. # some_function_that_needs_file_stream(file_stream)
  22. # 注意:使用完毕后如果不再需要,可以关闭流
  23. file_stream.close()

关键点说明:

  1. BytesIO 创建了一个内存中的二进制流对象,可以像文件对象一样操作
  2. doc.save(file_stream) 会直接将渲染后的文档写入内存流
  3. seek(0) 是必须的步骤,因为写入操作后流指针会停留在文件末尾,需要重置才能读取内容
  4. 这种方式完全避免了物理文件的生成,适合需要直接处理文件流的场景(如Web响应、云存储上传等)

这种方法在需要保持无文件操作、或需要即时处理文档内容的场景下非常有用,比如:

  • Web应用中直接返回生成的文档
  • 集成到需要文件流输入的工作流中
  • 避免临时文件清理的开销
  • 云函数等无持久化存储的环境

结合在python django项目里边的一点应用片段

  1. # 1. 构建安全路径
  2. template_name = "aicreate-plan-template.docx"
  3. template_dir = os.path.join(settings.MEDIA_ROOT, 'template_files')
  4. template_path = os.path.join(template_dir, template_name)
  5. # 2. 安全验证
  6. if not template_path.startswith(template_dir):
  7. raise serializers.ValidationError("Invalid file name")
  8. if not os.path.exists(template_path):
  9. raise serializers.ValidationError("Template file not found")
  10. # 需要填充的内容(可以调用AI接口生成)
  11. context = {
  12. 'name': '张三',
  13. 'order_id': 'ORD20230001',
  14. 'date': '2023-05-20',
  15. 'knowledge_objectives':"666",
  16. 'bibliography':"图标创意设计222"
  17. }
  18. # 存储的临时模板(直接用流读取就不需要了,不然存储后还要删除文件就浪费工作了)
  19. # outPutPath = os.path.join(template_dir, 'outputTemplate.docx')
  20. # 填充AI生成的内容并且导出word
  21. doc = DocxTemplate(template_path)
  22. doc.render(context)
  23. # doc.save(outPutPath)
  24. # -------------- AI生成内容end ---------------
  25. # 创建内存文件流
  26. memory_file = io.BytesIO()
  27. # 将渲染后的文档保存到内存流
  28. doc.save(memory_file)
  29. # 关键步骤:将流指针重置到开头
  30. memory_file.seek(0)
  31. # 现在 file_stream 就是包含渲染后文档的二进制流
  32. # 你可以像操作普通文件对象一样使用它:
  33. file_content = memory_file.read() # 获取二进制内容
  34. # 创建内存文件对象(持久化)
  35. # memory_file = io.BytesIO(file_content)
  36. memory_file.name = template_name # 设置文件名
  37. memory_file.size = len(file_content) # 设置文件大小
  38. # 创建DjangoFile对象
  39. file = DjangoFile(memory_file)
  40. file.content_type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
  41. # 计算MD5(使用内存数据)
  42. md5 = hashlib.md5(file_content).hexdigest()

欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

NET Core 使用 EF Code First

下面这些内容很老了看这篇:https://www.tnblog.net/aojiancc2/article/details/5365 项目使用多层,把数据库访问...

使用OLEDB读取不同版本Excel的连接字符串设置

使用OleBD读取excel的时候,excel不同的版本,连接字符串的写法也会不一样。///<summary> ///读取excel ///</su...

C 使用CancellationTokenSource取消多线程

有时间我们在使用多线程的时候,需要取消线程的执行,可以使用CancellationTokenSource来取消对Task开辟多线程的取消如下:...

使用爬虫刷csdn博客访问量

首先了解一下常见反爬虫的检测方法频率监测:有些网站会设置一种频率监测的机制,对于同一IP,若在一定时间内访问的速度超...

Idea下使用maven搭建SSM(一):SpringMVC

Spring MVC是一款基于MVC架构模式的轻量级Web框架,其目的是将Web开发模块化,对整体架构进行解耦,简化Web开发流程。下面...

Idea下使用maven搭建SSM(二):MyBatis

开发Web应用,数据的存储和处理往往离不开数据库和SQL语句。在使用Java开发的Web应用中,自然也少不了连接数据库的步骤。在...

使用 微软自带语音合成类库

//引入语音合成名称空间 usingSystem.Speech.Synthesis; classA { voidtest1() { //实例化并指定字符串播放合成读音 ...

如何使用图标像使用文字一样,使用文本图标的方法

1.首先在Iconfont-阿里巴巴矢量图标库上面找到你需要的图标然后加入你的购物车然后选择图标;注意:每个类型的图标会大小不...

使用七牛云的cdn服务,提高图片的加载速度

CDN介绍CDN的全称是Content Delivery Network,即内容分发网络。CDN加速主要是加速静态资源,如网站上面上传的图片、媒体,...

.net core 使用session

tip:net core 2.2后可以直接启用session了,不用在自己添加一次session依赖,本身就添加了使用nuget添加引用Microsoft.AspN...

使用OutLook发送邮件

publicstaticvoidOutlook(stringSubject,stringTextBody,stringFromAdd,stringFromPass,stringTo,stringCC,List<string&...

SQL Server 中使用游标

--声明一个游标 DECLAREMyCursorCURSOR FORSELECTTOP5FBookName,FBookCodingFROMTBookInfo//定义一个叫MyCursor的游标,...

Windows使用wireshark抓包小心得

wireshrak是个网络抓包工具,常用。但是在数据较大的网络环境中直接使用软件抓包会导致wireshark卡死。为什么呢 ?网卡瞬间...

Oracle自定义函数的简单使用

一.最最最简单的返回一个数字的函数createorreplacefunctionfun_show returnint--申明返回值 as begin return1; end;...

Oracle事务的简单使用

事务:  事务是一个整体,这些操作要么全部执行成功,要么全部不执行。使用事务的原因:保证数据的安全有效。事务的四个特...

Oracle使用游标

其实游标就是把查询的结果放入游标中,然后在去游标里边读取。相当于使用游标做了一个中转,而游标是可以作为参数进行传递...