突然间,就在 Frappe 更新之后,你一打开打印视图或尝试下载 PDF,所有打印格式(或某个特定格式)就立刻失败了。错误信息会指出行号,但不会说明是哪个格式,所以很难看出该修什么。
错误信息
你会看到以下之一,可能是在打印视图中的对话框里,也可能是在 PDF/下载响应中:
Print Format Error
Error in print format on line 19: 'NoneType' object is not callable
或者是更完整的版本,出现在你从 PDF 下载链接得到的服务器错误页面中:
File "apps/frappe/frappe/templates/print_formats/standard.html", line 19, in top-level template code
{{ render_field(df, doc, no_of_cols) }}
File "env/lib/python3.x/site-packages/jinja2/sandbox.py", line 401, in call
return __context.call(__obj, *args, **kwargs)
TypeError: 'NoneType' object is not callable
...
frappe.exceptions.PrintFormatError: Error in print format on line 19: 'NoneType' object is not callable
一个相关的版本会显示 KeyError 或其他 Jinja 异常,而不是 NoneType,但同样呈现”所有打印格式都挂了”的模式。原因和下面的修复方法是一样的。
为什么会发生这种情况
打印格式是通过 Jinja 渲染的:html 模板通过 Jinja 的沙箱调用 Python 函数并读取文档字段。'NoneType' object is not callable 的意思是 Jinja 试图把某个东西当作函数来调用,但那个东西求值结果是 None——通常是一个空白字段(当 备注 为空时就是 {{ doc.remarks() }}),或者是沙箱无法解析的模板宏。
大多数”更新后所有打印格式都坏了”的报告,都可以追溯到 Frappe Framework 本身的一个短暂回归问题,出在每个内置打印格式和基于 Builder 的打印格式共用的 standard.html 模板中——一次核心改动导致其中一个模板宏在两次发布之间的短暂窗口内返回了 None。Frappe 会很快修复这些问题(几小时到几天内),并以补丁版本的形式发布修复,但在你的站点升级到那个版本之前,每次打印和 PDF 都会以同样的方式失败。同一个模板上已经不止一次发生过这种情况,所以”先更新,看看是否修好了”是一个合理的首选操作,而不是一次性的做法。
如果只有一个打印格式失败,其余的都正常,那原因就在那个格式本身:某个自定义打印格式(或合作伙伴定制过的格式)的 Jinja 或自定义 HTML 调用了某个字段、doctype 方法或打印模板钩子,而某个应用更新将其删除、重命名,或对某些文档留空了。
如何修复
- 打开文档,点击打印图标,把 打印格式 切换到另一个(某个内置格式,或 标准)。如果它能正常渲染,问题就出在你之前用的那个格式上——跳到第 4 步。如果所有格式都失败,问题就在 Frappe 本身——继续第 2 步。
- 阅读 traceback,确认它与本问题相符,并找出失败的位置。在打印视图中,重新选择失败的格式以查看对话框;从 PDF 下载链接(或附带 PDF 的邮件/报表)中,改为打开完整的服务器错误页面——那里有完整的 traceback。
最后一行会指出异常,对于打印格式相关的错误,还会指出你模板中的行号:
如果失败发生在后台任务中(定时报表、附带 PDF 的邮件)——也就是说没有人能看到对话框——请从 Awesome Bar 打开 错误日志,查找同一时间附近针对同一文档的条目;它带有相同的 traceback。
3. 检查你的应用是否处于匹配的、当前的版本。打开 帮助 → 关于(或在 bench 目录下运行 bench version),对比 已安装应用 列表:Frappe Framework、你的主应用(ERPNext 等)以及任何自定义应用都应处于同一版本线(全部 v15,或全部 v16——不要混用),并且都不应落后于该版本线的最新补丁版本。
如果 Frappe Framework 落后了,请更新它:
bench update
bench --site [site-name] migrate
bench build
bench clear-cache
bench clear-website-cache
即使 bench update 无错误地完成,bench build 和两个清除缓存的命令也很重要——过期的 JS/CSS 构建或缓存的页面可能会继续显示旧的、损坏的行为。在 Frappe Cloud 上,你不需要自己运行这些:公共(共享)bench 会在其每周发布日自动更新;在私有 bench 组上,打开站点仪表板中的 更新 并应用待处理的更新。
4. 如果只有你自己的自定义打印格式失败,请打开它(打印格式 列表,或从打印视图中的 自定义),检查 traceback 指出的那一行。查找某个字段引用——它可能对某些文档是空白的,却被当作函数调用(用 {{ doc.some_field() }} 而不是 {{ doc.some_field }}),或者查找从某个应用更新改变了的模板路径导入的宏。修复模板,或者如果该格式是在更新之前构建的,就基于当前的标准布局重新创建它。
如何预防
- 让 Frappe Framework 和其他应用保持在同一版本线,并处于该版本线的最新补丁版本——大多数这类故障都会在补丁版本中修复,保持最新就能避免它们。
- 在任何更新之后,在团队重新开始使用站点之前,用你依赖的每个自定义打印格式各打印一份文档。
如果这样仍无法解决
请提交支持工单,并附上:确切的错误文本、打印格式名称、从 帮助 → 关于 中获取的 Frappe Framework 和应用版本,以及你当时正在打印的文档。如果你有完整的回溯信息(来自服务器错误页面或错误日志),请一并附上——这是支持团队确认该问题属于已知的 Framework 回归问题,还是你自己的打印格式中的问题的最快方式。
相关内容
- 打印
- 在哪里可以找到标准打印格式