背景需求:
新搭档是“语言文字”工作负责人,未开学就发布了“国旗下讲话”的模板。
发言班级安排表
班主任填写模板
之前我长期在总园带班,总园班级多(10个以上),一学期最多轮到3次,所以就直接做了。
但是到了一分园只有4个班,就是4周轮到一次,一共5次。频率很高。(二分园也只有4个班)
既然图表里已有周次、日期、发言题目、轮值院长、班级的信息,为什么不用python的模板写入方式把模板都做好,样式规范统一。
一、制作excle表:把word里面的表格复制到excle内,拆分表格,修改英文标题、更改日期形式,添加班主任
周次week,从汉字变成数字,拖拉变成数字日期
日期date,原来是9月8日(只有年月),把一列复制到deepseek,让它改成年.月.日的格式
班主任teachers:手动复制教工名单
行政老师leader +班级classroom ,复制到AI,拆分成表格形式两列
虽然没有孩子,但是标题写上student1-student6,
二、word模板修改
1、把基础信息填好,学生所在位置留好,
2、教师讲话内容只留一行,黏贴文字后表格自然会变长
3、活动掠影只留一行,插入两张照片后表格自然会变长
三、编程代码(4份)
把安排表和模板和以前的一份“python模板插入代码”放入AI编程
代码展示1.0
'''
国旗下讲话模板批量01 没有学生名字
deep seek 、阿夏
20250824
'''
import pandas as pd
from docxtpl import DocxTemplate
import os
from docx import Document
# 设置路径
zpath = r'C:Usersjg2yXRZOneDrive桌面202509一分院 国旗下讲话'
temp = zpath + r'模版'
os.makedirs(temp, exist_ok=True)
# 读取安排表x
schedule = pd.read_excel(zpath + '模版国旗下的讲话总安排(一分部) 2025.9.xlsx')
# 首先检查模板文件是否存在且是有效的Word文件
template_path = zpath + '模板一分园(小 1 班)国旗下的讲话(第 2 周).docx'
if not os.path.exists(template_path):
print(f"错误:模板文件不存在 - {template_path}")
exit()
try:
# 尝试打开模板文件检查是否有效
doc = Document(template_path)
print("模板文件检查通过,开始生成文档...")
except Exception as e:
print(f"模板文件无效: {e}")
print("请确保模板文件是有效的Word文档 (.doc 或 .docx)")
exit()
# 遍历安排表的每一行
for index, row in schedule.iterrows():
try:
# 每次重新读取模板,确保每次都是干净的模板
tpl = DocxTemplate(template_path)
# 构建上下文数据
context = {
"date": str(row['date']), # 确保日期是字符串
"week": str(row['week']),
"teachers": str(row['teachers']),
"classroom": str(row['classroom']),
"topic": str(row['topic']),
"leader": str(row['leader']),
"s1": str(row['s1']) if pd.notna(row['s1']) else "",
"s2": str(row['s2']) if pd.notna(row['s2']) else "",
"s3": str(row['s3']) if pd.notna(row['s3']) else "",
"s4": str(row['s4']) if pd.notna(row['s4']) else "",
"s5": str(row['s5']) if pd.notna(row['s5']) else ""
}
# 渲染模板
tpl.render(context)
# 保存文件,文件名包含周次和班级信息
filename = f"国旗下的讲话_{row['week']}_{row['classroom']}.docx"
full_path = os.path.join(temp, filename)
tpl.save(full_path)
print(f"已生成: {filename}")
except Exception as e:
print(f"生成第{index+1}行数据时出错: {str(e)}")
continue
print("所有文档生成完成!")
除了孩子名字是空的,其他时间、班级、周次、班主任、行政、主题内容都有了
那么5个学生的名单怎么插入?把我收集的22个班级点名册放入文件夹里。
把班级信息表excle和之前的excle都上传,并在刚才可质性代码最后写上如何提取小班孩子的信息(都是25人,正好轮5次,每次就拆分5人)
运行后报错,我发现一分院是2个托班(每班20人),2个小班(每班25人)
代码展示2.0(只抽小1-2、托1-2)
'''
国旗下讲话模板批量02 随机抽取5个一组的孩子名字
deep seek 、阿夏
20250824
'''
import pandas as pd
from docxtpl import DocxTemplate
import os
from docx import Document
import numpy as np
# 设置路径
zpath = r'C:Usersjg2yXRZOneDrive桌面202509一分院 国旗下讲话'
temp = zpath + r'模版'
os.makedirs(temp, exist_ok=True)
# 读取班级信息表
class_info_path = zpath + '班级信息表.xlsx'
class_info = pd.read_excel(class_info_path, sheet_name=None) # 读取所有工作表
# 读取安排表
schedule_path = zpath + '模版国旗下的讲话总安排(一分部) 2025.9.xlsx'
schedule = pd.read_excel(schedule_path)
# 确保s1-s5列是字符串类型
for col in ['s1', 's2', 's3', 's4', 's5']:
if col in schedule.columns:
schedule[col] = schedule[col].astype(str)
# 将"nan"转换为空字符串
schedule[col] = schedule[col].replace('nan', '')
# 为每个班级创建学生姓名分组(托班4人一组,小班5人一组)
class_groups = {}
for sheet_name, df in class_info.items():
if sheet_name not in ['模板'] and '班' in sheet_name: # 跳过模板表,只处理班级表
# 过滤掉空姓名
students = df[df['姓名'].notna()]['姓名'].tolist()
# 根据班级类型确定每组人数
if '托' in sheet_name:
# 托班:4人一组
group_size = 4
elif '小' in sheet_name:
# 小班:5人一组
group_size = 5
else:
# 其他班级默认5人一组
group_size = 5
# 按指定人数分组
groups = [students[i:i+group_size] for i in range(0, len(students), group_size)]
class_groups[sheet_name] = groups
print(f"班级 {sheet_name}: {len(students)} 名学生,分成 {len(groups)} 组(每组{group_size}人)")
# 更新安排表中的学生姓名
for index, row in schedule.iterrows():
classroom = row['classroom']
# 将"小1班"转换为"小1班"格式(去掉括号)
clean_classroom = classroom.replace('(', '').replace(')', '')
if clean_classroom in class_groups:
groups = class_groups[clean_classroom]
# 使用循环分组,如果组数不够就从头开始
group_index = index % len(groups)
students = groups[group_index]
# 更新安排表
for i in range(5): # s1-s5最多5个位置
col_name = f's{i+1}'
if i < len(students):
schedule.at[index, col_name] = students[i]
else:
schedule.at[index, col_name] = ""
# 保存更新后的安排表
updated_schedule_path = zpath + '模版国旗下的讲话总安排(一分部) 2025.9_已填充.xlsx'
schedule.to_excel(updated_schedule_path, index=False)
print(f"已保存更新后的安排表: {updated_schedule_path}")
# 现在使用更新后的安排表生成文档
# 首先检查模板文件是否存在且是有效的Word文件
template_path = zpath + '模板一分园(小 1 班)国旗下的讲话(第 2 周).docx'
if not os.path.exists(template_path):
print(f"错误:模板文件不存在 - {template_path}")
exit()
try:
# 尝试打开模板文件检查是否有效
doc = Document(template_path)
print("模板文件检查通过,开始生成文档...")
except Exception as e:
print(f"模板文件无效: {e}")
print("请确保模板文件是有效的Word文档 (.doc 或 .docx)")
exit()
# 遍历安排表的每一行生成文档
for index, row in schedule.iterrows():
try:
# 每次重新读取模板,确保每次都是干净的模板
tpl = DocxTemplate(template_path)
# 格式化班级名称(小1班 -> 小(1)班)
classroom_str = str(row['classroom'])
if len(classroom_str) >= 3:
formatted_classroom = f"{classroom_str[0]}({classroom_str[1]}){classroom_str[2:]}"
else:
formatted_classroom = classroom_str
# 构建上下文数据
context = {
"date": str(row['date']),
"week": str(row['week']),
"teachers": str(row['teachers']),
"classroom": formatted_classroom,
"topic": str(row['topic']),
"leader": str(row['leader']),
"s1": str(row['s1']) if pd.notna(row['s1']) and str(row['s1']) != 'nan' else "",
"s2": str(row['s2']) if pd.notna(row['s2']) and str(row['s2']) != 'nan' else "",
"s3": str(row['s3']) if pd.notna(row['s3']) and str(row['s3']) != 'nan' else "",
"s4": str(row['s4']) if pd.notna(row['s4']) and str(row['s4']) != 'nan' else "",
"s5": str(row['s5']) if pd.notna(row['s5']) and str(row['s5']) != 'nan' else ""
}
# 渲染模板
tpl.render(context)
# 格式化周次(第1周 -> 第01周)
week_num = str(row['week']).replace('第', '').replace('周', '')
try:
week_formatted = f"第{int(week_num):02d}周"
except:
week_formatted = str(row['week'])
# 保存文件
filename = f"{week_formatted}_一分园_{row['classroom']}_国旗下的讲话_({row['topic']}).docx"
full_path = os.path.join(temp, filename)
tpl.save(full_path)
print(f"已生成: {filename}")
except Exception as e:
print(f"生成第{index+1}行数据时出错: {str(e)}")
continue
print("所有文档生成完成!")
这里还改了docx的名称,使它看上更为规范
但是我核对了一下小2班的名单,发现小2班第1次讲话(第3周)里面出现的五个姓名是5-10号,我希望是1-5号,小2班第5次讲话(第19周)里面出现的五个姓名是11-15号,我希望是20-25号,
显然代码里抽取5个一组的顺序是打乱的。
代码展示3.0(按顺序5个5个抽取)
'''
国旗下讲话模板批量03 按照学号顺序依次出现55个一组的孩子名字
deep seek 、阿夏
20250824
'''
import pandas as pd
from docxtpl import DocxTemplate
import os
from docx import Document
import numpy as np
# 设置路径
zpath = r'C:Usersjg2yXRZOneDrive桌面202509一分院 国旗下讲话'
temp = zpath + r'202509一分园国旗下讲话模版'
os.makedirs(temp, exist_ok=True)
# 读取班级信息表
class_info_path = zpath + '班级信息表.xlsx'
class_info = pd.read_excel(class_info_path, sheet_name=None) # 读取所有工作表
# 读取安排表
schedule_path = zpath + '模版国旗下的讲话总安排(一分部) 2025.9.xlsx'
schedule = pd.read_excel(schedule_path)
# 确保s1-s5列是字符串类型
for col in ['s1', 's2', 's3', 's4', 's5']:
if col in schedule.columns:
schedule[col] = schedule[col].astype(str)
# 将"nan"转换为空字符串
schedule[col] = schedule[col].replace('nan', '')
# 为每个班级创建学生姓名列表(按学号排序)
class_students = {}
for sheet_name, df in class_info.items():
if sheet_name not in ['模板'] and '班' in sheet_name: # 跳过模板表,只处理班级表
# 按学号排序并过滤掉空姓名
students = df[df['姓名'].notna()].sort_values('学号')['姓名'].tolist()
class_students[sheet_name] = students
print(f"班级 {sheet_name}: {len(students)} 名学生")
# 为每个班级创建索引跟踪器
class_index_tracker = {class_name: 0 for class_name in class_students.keys()}
# 更新安排表中的学生姓名
for index, row in schedule.iterrows():
classroom = row['classroom']
# 将"小1班"转换为"小1班"格式(去掉括号)
clean_classroom = classroom.replace('(', '').replace(')', '')
if clean_classroom in class_students:
students = class_students[clean_classroom]
current_index = class_index_tracker[clean_classroom]
# 根据班级类型确定每组人数
if '托' in clean_classroom:
# 托班:4人一组
group_size = 4
elif '小' in clean_classroom:
# 小班:5人一组
group_size = 5
else:
# 其他班级默认5人一组
group_size = 5
# 获取当前组的5名学生
selected_students = []
for i in range(group_size):
if current_index < len(students):
selected_students.append(students[current_index])
current_index += 1
else:
# 如果到末尾,从头开始
current_index = 0
selected_students.append(students[current_index])
current_index += 1
# 更新索引跟踪器
class_index_tracker[clean_classroom] = current_index
# 更新安排表
for i in range(5): # s1-s5最多5个位置
col_name = f's{i+1}'
if i < len(selected_students):
schedule.at[index, col_name] = selected_students[i]
else:
schedule.at[index, col_name] = ""
print(f"第{index+1}行 {clean_classroom}: {selected_students}")
# 保存更新后的安排表
updated_schedule_path = zpath + '模版国旗下的讲话总安排(一分部) 2025.9_已填充.xlsx'
schedule.to_excel(updated_schedule_path, index=False)
print(f"已保存更新后的安排表: {updated_schedule_path}")
# 现在使用更新后的安排表生成文档
# 首先检查模板文件是否存在且是有效的Word文件
template_path = zpath + '模板一分园(小 1 班)国旗下的讲话(第 2 周).docx'
if not os.path.exists(template_path):
print(f"错误:模板文件不存在 - {template_path}")
exit()
try:
# 尝试打开模板文件检查是否有效
doc = Document(template_path)
print("模板文件检查通过,开始生成文档...")
except Exception as e:
print(f"模板文件无效: {e}")
print("请确保模板文件是有效的Word文档 (.doc 或 .docx)")
exit()
# 遍历安排表的每一行生成文档
for index, row in schedule.iterrows():
try:
# 每次重新读取模板,确保每次都是干净的模板
tpl = DocxTemplate(template_path)
# 格式化班级名称(小1班 -> 小(1)班)
classroom_str = str(row['classroom'])
if len(classroom_str) >= 3:
formatted_classroom = f"{classroom_str[0]}({classroom_str[1]}){classroom_str[2:]}"
else:
formatted_classroom = classroom_str
# 构建上下文数据
context = {
"date": str(row['date']),
"week": str(row['week']),
"teachers": str(row['teachers']),
"classroom": formatted_classroom,
"topic": str(row['topic']),
"leader": str(row['leader']),
"s1": str(row['s1']) if pd.notna(row['s1']) and str(row['s1']) != 'nan' else "",
"s2": str(row['s2']) if pd.notna(row['s2']) and str(row['s2']) != 'nan' else "",
"s3": str(row['s3']) if pd.notna(row['s3']) and str(row['s3']) != 'nan' else "",
"s4": str(row['s4']) if pd.notna(row['s4']) and str(row['s4']) != 'nan' else "",
"s5": str(row['s5']) if pd.notna(row['s5']) and str(row['s5']) != 'nan' else ""
}
# 渲染模板
tpl.render(context)
# 格式化周次(第1周 -> 第01周)
week_num = str(row['week']).replace('第', '').replace('周', '')
try:
week_formatted = f"第{int(week_num):02d}周"
except:
week_formatted = str(row['week'])
# 保存文件
filename = f"{week_formatted}_一分园_{row['classroom']}_国旗下的讲话_({row['topic']}).docx"
full_path = os.path.join(temp, filename)
tpl.save(full_path)
print(f"已生成: {filename}")
except Exception as e:
print(f"生成第{index+1}行数据时出错: {str(e)}")
continue
print("所有文档生成完成!")
这次正确了,出现的第1组的5个孩子的名字
最后生成了一个包含所有基础信息的模板文件夹
现在就可以打包发给我搭档了
四、合并docx,在线编辑
平时我感觉国旗下讲话都是学期结束(2026年1月)统一提交的,一个个文件发出去,再收回来,也很费时,需要看核对哪个班级没有写。最后一个一个文件打开再打印、排序也麻烦。
所以我想把模板文件夹里的所有docx合并成一个docx,然后金山表单共享填写。
deepseek几乎每天都有一段时间卡死,换豆包改写
代码展示4.0(批量做各班的表+合并所有表+金山WPS在线共享编辑)
'''
国旗下讲话模板批量04 按照学号顺序依次出现5个5个一组的孩子名字+合并docx,在线填写
deep seek 、豆包、阿夏
20250824
'''
import pandas as pd
from docxtpl import DocxTemplate
import os
from docx import Document
import numpy as np
# 设置路径
zpath = r'C:Usersjg2yXRZOneDrive桌面202509一分院 国旗下讲话'
temp = zpath + r'202509一分园国旗下讲话模版'
os.makedirs(temp, exist_ok=True)
# 读取班级信息表
class_info_path = zpath + '班级信息表.xlsx'
class_info = pd.read_excel(class_info_path, sheet_name=None) # 读取所有工作表
# 读取安排表
schedule_path = zpath + '模版国旗下的讲话总安排(一分部) 2025.9.xlsx'
schedule = pd.read_excel(schedule_path)
# 确保s1-s5列是字符串类型
for col in ['s1', 's2', 's3', 's4', 's5']:
if col in schedule.columns:
schedule[col] = schedule[col].astype(str)
# 将"nan"转换为空字符串
schedule[col] = schedule[col].replace('nan', '')
# 为每个班级创建学生姓名列表(按学号排序)
class_students = {}
for sheet_name, df in class_info.items():
if sheet_name not in ['模板'] and '班' in sheet_name: # 跳过模板表,只处理班级表
# 按学号排序并过滤掉空姓名
students = df[df['姓名'].notna()].sort_values('学号')['姓名'].tolist()
class_students[sheet_name] = students
print(f"班级 {sheet_name}: {len(students)} 名学生")
# 为每个班级创建索引跟踪器
class_index_tracker = {class_name: 0 for class_name in class_students.keys()}
# 更新安排表中的学生姓名
for index, row in schedule.iterrows():
classroom = row['classroom']
# 将"小1班"转换为"小1班"格式(去掉括号)
clean_classroom = classroom.replace('(', '').replace(')', '')
if clean_classroom in class_students:
students = class_students[clean_classroom]
current_index = class_index_tracker[clean_classroom]
# 根据班级类型确定每组人数
if '托' in clean_classroom:
# 托班:4人一组
group_size = 4
elif '小' in clean_classroom:
# 小班:5人一组
group_size = 5
else:
# 其他班级默认5人一组
group_size = 5
# 获取当前组的5名学生
selected_students = []
for i in range(group_size):
if current_index < len(students):
selected_students.append(students[current_index])
current_index += 1
else:
# 如果到末尾,从头开始
current_index = 0
selected_students.append(students[current_index])
current_index += 1
# 更新索引跟踪器
class_index_tracker[clean_classroom] = current_index
# 更新安排表
for i in range(5): # s1-s5最多5个位置
col_name = f's{i+1}'
if i < len(selected_students):
schedule.at[index, col_name] = selected_students[i]
else:
schedule.at[index, col_name] = ""
print(f"第{index+1}行 {clean_classroom}: {selected_students}")
# 保存更新后的安排表
updated_schedule_path = zpath + '模版国旗下的讲话总安排(一分部) 2025.9_已填充.xlsx'
schedule.to_excel(updated_schedule_path, index=False)
print(f"已保存更新后的安排表: {updated_schedule_path}")
# 现在使用更新后的安排表生成文档
# 首先检查模板文件是否存在且是有效的Word文件
template_path = zpath + '模板一分园(小 1 班)国旗下的讲话(第 2 周).docx'
if not os.path.exists(template_path):
print(f"错误:模板文件不存在 - {template_path}")
exit()
try:
# 尝试打开模板文件检查是否有效
doc = Document(template_path)
print("模板文件检查通过,开始生成文档...")
except Exception as e:
print(f"模板文件无效: {e}")
print("请确保模板文件是有效的Word文档 (.doc 或 .docx)")
exit()
# 遍历安排表的每一行生成文档
for index, row in schedule.iterrows():
try:
# 每次重新读取模板,确保每次都是干净的模板
tpl = DocxTemplate(template_path)
# 格式化班级名称(小1班 -> 小(1)班)
classroom_str = str(row['classroom'])
if len(classroom_str) >= 3:
formatted_classroom = f"{classroom_str[0]}({classroom_str[1]}){classroom_str[2:]}"
else:
formatted_classroom = classroom_str
# 构建上下文数据
context = {
"date": str(row['date']),
"week": str(row['week']),
"teachers": str(row['teachers']),
"classroom": formatted_classroom,
"topic": str(row['topic']),
"leader": str(row['leader']),
"s1": str(row['s1']) if pd.notna(row['s1']) and str(row['s1']) != 'nan' else "",
"s2": str(row['s2']) if pd.notna(row['s2']) and str(row['s2']) != 'nan' else "",
"s3": str(row['s3']) if pd.notna(row['s3']) and str(row['s3']) != 'nan' else "",
"s4": str(row['s4']) if pd.notna(row['s4']) and str(row['s4']) != 'nan' else "",
"s5": str(row['s5']) if pd.notna(row['s5']) and str(row['s5']) != 'nan' else ""
}
# 渲染模板
tpl.render(context)
# 格式化周次(第1周 -> 第01周)
week_num = str(row['week']).replace('第', '').replace('周', '')
try:
week_formatted = f"第{int(week_num):02d}周"
except:
week_formatted = str(row['week'])
# 保存文件
filename = f"{week_formatted}_一分园_{row['classroom']}_国旗下的讲话_({row['topic']}).docx"
full_path = os.path.join(temp, filename)
tpl.save(full_path)
print(f"已生成: {filename}")
except Exception as e:
print(f"生成第{index+1}行数据时出错: {str(e)}")
continue
print("所有文档生成完成!")
除了模板文件夹,还有一份合并docx
发现回车符和分页符不在一行上,就会多占一个空行,
改了几次,还是有回车和换行符,
最后我在word的模板里把这个回车符间距从1.5倍改成固定值1磅
现在都看不见回车符,分页符看上去贴着表格(实际回车符存在)可以让表格最大化控制在一页内,又能让文字尽可能多一点
把word发到手机,用WPS转成可编辑的文件。
五、发给同事,学期再用
搭档表示很有趣。
感悟:
1、Ai编程批量,实现模板的个性化批量制作,提高数据准确性(基本信息都填好,格式完全相同,减少人工自主填写出现的差异,还能根据需求批量调整)
2、AI数据整理:快速将各类数据转化为需要的样式。不用excle进行转换。
3、共享编辑:WPS的共享编辑可以实时更新数据,实现单一文本(如果大家都自己编辑自己的,合并也需要时间和经历)便于快速检查,提醒填写,最终下载一个文件,能快速批量打印。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END
暂无评论内容