You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySimpleGUI结合docxtpl渲染Word时提示'Check'未定义报错

问题现象

开发基于PySimpleGUI + docxtpl的住宿发票录入生成工具时,程序运行触发Jinja2模板变量未定义错误:

  • 终端运行报错:
File "<template>", line 1, in top-level template code
jinja2.exceptions.UndefinedError: 'Check' is undefined
  • 调试模式报错:
Exception has occurred: UndefinedError 'Check' is undefined

原实现代码如下:

import PySimpleGUI as sg
from pathlib import Path
import datetime
from docxtpl import DocxTemplate


dokumen_path = Path(__file__).parent / "word_template.docx"
doc = DocxTemplate(dokumen_path)

def tanggal_waktu():
    hari = datetime.datetime.today()
    return hari

layout = [
    [sg.Text("GUEST NAME"), sg.Input(key="NAMA", do_not_clear=False)],
    [sg.Text("CHECK-IN"), sg.Input(key="Check-in", do_not_clear=False)],
    [sg.Text("CHECK-OUT"), sg.Input(key="Check-out", do_not_clear=False)],
    [sg.Text("ROOM NO"), sg.Input(key="KAMAR",do_not_clear=False)],
    [sg.Text("TYPE"), sg.Input(key="TIPE",do_not_clear=False)],
    [sg.Text("PERSON"), sg.Input(key="ORANG", do_not_clear=False)],
    [sg.Text("ROOM CHARGE"), sg.Input(key="RC",do_not_clear=False),],
    [sg.Button("Submit"), sg.Exit()],
]

window = sg.Window("Invoice Palm Garden Guest House", layout, element_justification="right")

while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == "Exit":
        break
    if event == "Submit":
        print(values)
        values["D/T"] = tanggal_waktu()
        values["TOTAL"] = int(values["RC"])
        doc.render(values)
        output_path = Path(__file__).parent / f"{values['NAMA']}-Invoice.docx"
        doc.save(output_path)
        sg.popup("File Saved")
    else:
        pass


window.close()

配套使用的Word模板见提供的参考截图。

报错根因
  • 错误由Jinja2模板语法解析规则和变量名不兼容导致:代码中给入住、离店输入框设置的key为Check-in、Check-out,包含横杠-特殊字符。如果在Word模板中直接写{{ Check-in }}这类占位符,Jinja2会把横杠识别为减法运算符,将表达式解析为「变量Check 减去 变量in」,执行时找不到名为Check的变量,就会抛出未定义错误。
修复方案

推荐使用改动最小的方案1:

方案1:修改键名为下划线命名(推荐)

Jinja2原生支持下划线分隔的标识符,无需特殊写法:

  1. 修改Python代码中layout部分的两个输入框key,把横杠替换为下划线:
    # 原代码
    [sg.Text("CHECK-IN"), sg.Input(key="Check-in", do_not_clear=False)],
    [sg.Text("CHECK-OUT"), sg.Input(key="Check-out", do_not_clear=False)],
    # 修改为
    [sg.Text("CHECK-IN"), sg.Input(key="Check_in", do_not_clear=False)],
    [sg.Text("CHECK-OUT"), sg.Input(key="Check_out", do_not_clear=False)],
    
  2. 打开Word模板文件,把对应的占位符同步修改:
    • 将{{ Check-in }}替换为{{ Check_in }}
    • 将{{ Check-out }}替换为{{ Check_out }}
      修改后重新运行程序即可正常渲染生成文档。

方案2:保留原有键名,调整模板取值语法

如果不想修改Python代码中的key定义,可以调整模板里的变量写法,通过字典键访问的形式绕过运算符解析:

  1. 把代码中doc.render(values)修改为doc.render({"form_data": values}),将所有表单值包裹在form_data字典下传入模板
  2. 修改Word模板中所有占位符,增加form_data.前缀,对于带横杠的键用方括号取值:
    • 原{{ NAMA }}改为{{ form_data.NAMA }}
    • 原{{ Check-in }}改为{{ form_data['Check-in'] }}
    • 原{{ Check-out }}改为{{ form_data['Check-out'] }}
    • 其余KAMAR/TIPE/ORANG/RC/D/T/TOTAL等变量同步增加form_data.前缀即可。

内容的提问来源于stack exchange,提问作者StressCodingCok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 06:06:47