首页
/ ToolJet Run Python Code 数据源完全指南:在组件、查询与转换中编写 Python 逻辑

ToolJet Run Python Code 数据源完全指南:在组件、查询与转换中编写 Python 逻辑

2026-09-08 23:55:42作者:余洋婵Anita

本文以 ToolJet 仓库中的 run-py.md 文档为主线,系统讲解 Run Python Code(runpy) 这一内置数据源的创建、能力边界与最佳实践:如何用 Python 触发组件动作、运行其他查询并读取其结果、读写变量、在数据转换(Transformations)中复用 Python 逻辑,以及把查询结果绑定回组件渲染。读完本文,你将能直接在 ToolJet 的 App Builder 中编写可复用的 Python 查询,实现比纯低代码表达式更灵活的数据处理与交互编排。

Run Python Code 是 ToolJet 内置的自定义代码类数据源,它让你不依赖 JavaScript 就能在应用内编写并执行 Python,用来与页面上的组件、已建立的查询交互,从而自定义动作逻辑与数据处理方式。在源码层面,它是与 restapirunjstooljetdbworkflows 并列的一种静态数据源类型 runpy(参见 DefaultDataSourceKinds 常量),其 Python 代码实际是在浏览器端通过 Pyodide(WebAssembly 版 CPython)执行,而非在服务器端运行。

在 ToolJet 中新建查询并选择 Run Python Code 数据源

一、创建一条 Run Python Code 查询

  1. 在 App Builder 中打开 Query Manager(查询管理器)
  2. 点击 Add(添加),在数据源列表中选择 Run Python Code
  3. 代码编辑区会自动打开一个 Python 语言模式的多行编辑器,输入代码后 保存并运行(Save and Run)

从实现上看,这个编辑器由 Runpy.jsx 渲染:它基于 CodeHinter 组件,设置了 lang="python"、默认高度 400px,输入内容通过 changeOption(this, 'code', value) 写回查询配置中的 options.code 字段。因此每条 Run Python 查询本质上就是一个 code 配置项 + runpy 数据源类型的组合。

执行时,前端会通过 loadPyodidePYODIDE_BASE_URL 加载 Pyodide 运行时:

export const loadPyodide = async () => {
  const pyodide = await window.loadPyodide({ indexURL: process.env.PYODIDE_BASE_URL });
  return pyodide;
};

理解“Python 跑在浏览器里”这一点,对后面判断哪些库可用、哪些网络能力受限非常关键。

二、用 Python 触发组件专属动作

Run Python Code 最典型的使用场景之一,是从 Python 代码里调用组件的专属动作(Component Specific Actions),把计算结果写回组件状态。

官方文档给出了一个完整示例:先用 Text 组件在画布上放置一个文本框(其组件名默认为 text1),再新建一条 Run Python Code 查询,粘贴如下代码并运行:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def myfunc(self):
        return "Hello my name is " + self.name

p1 = Person(tj_globals.currentUser.firstName, 36)

components.text1.setText(p1.myfunc())

代码含义拆解:

  • 定义了一个普通 Python 类 Person,包含构造函数与返回问候语的 myfunc 方法;
  • tj_globals.currentUser.firstName 直接读取 ToolJet 暴露的全局变量,把当前登录用户的名字注入 Python 对象——这说明 Python 与 ToolJet 运行时共享了同一套上下文数据;
  • 最后一行的 components.text1.setText(...) 是一个 组件专属动作,等价于在 UI 上调用 Text 组件的 setText 方法,将其 value 更新为 myfunc() 的返回值。

运行后,画布上的 Text 组件便会显示类似 Hello my name is <你的名字> 的内容。把复杂字符串拼接、格式化甚至算法逻辑交给 Python,再通过组件动作写回界面,正是该数据源的核心价值。

三、在 Python 中触发其他查询

Run Python Code 可以直接驱动应用里已有的查询。文档给出两种等价写法:

actions.runQuery('getSalesData')
# 将 getSalesData 替换为你的查询名称

或:

queries.getSalesData.run()
# 将 getSalesData 替换为你的查询名称

两者都会触发名为 getSalesData 的查询开始执行。区别在于语义:actions.runQuery 走的是与事件动作(Event Handler)相同的“动作”通道,适合在 Python 逻辑的任意位置按名称触发;queries.<name>.run() 则通过查询对象 API 触发,触发后还可以配合下一小节的取值方法拿到结果。

四、获取查询返回的数据

如果你需要立即读取某查询的返回结果继续处理,可以先 await 运行它,再通过查询对象的取值方法获取数据。运行 Python 的上下文支持异步(Pyodide 基于事件循环),所以可以使用 await

触发查询并获取其数据(Data)

await queries.getSalesData.run()
# 将 getSalesData 替换为你的查询名称

value = queries.getSalesData.getData()
# 将 getSalesData 替换为你的查询名称

value

getData() 返回查询处理后的数据(例如已应用默认映射、便于展示的数据结构)。注意最后一行直接把 value 作为代码块末尾表达式——Run Python Code 会像 REPL 一样把最后一个表达式的值作为查询输出,value 会同时显示在查询结果面板中,供后续绑定或调试。

触发查询并获取其原始数据(Raw Data)

await queries.getCustomerData.run()
# 将 getCustomerData 替换为你的查询名称

value = queries.getCustomerData.getRawData()
# 将 getCustomerData 替换为你的查询名称

value

getRawData() 返回 API/数据源返回的未经处理的原始响应。当 ToolJet 对数据做过归一化而你想拿最原始的 JSON 做自定义解析时,优先使用它。

触发查询并读取其加载状态(Loading State)

await queries.getTodos.run()
# 将 getTodos 替换为你的查询名称

value = queries.getTodos.getLoadingState()
# 将 getTodos 替换为你的查询名称

value

getLoadingState() 返回布尔值,标识查询当前是否仍在执行中。你可以在 Python 中据此做条件分支,例如:等待数据就绪后继续、否则提前返回。

需要提醒的是,await queries.<name>.run() 会阻塞 Python 执行直到查询完成,因此它天然适合“先取数、再计算、最后写回组件”的串行流程,避免竞态问题。

五、在 Python 中读写变量与页面变量

Run Python Code 还暴露了变量操作 API,可以读写应用级变量(Variables)页面变量(Page Variables),让 Python 与页面其余部分共享状态。

设置变量

actions.setVariable('color', 'blue')
# 将 color 替换为你想使用的变量名

设置后立即读取该变量

actions.setVariable('mode', 'dark')
# 将 mode 替换为你想使用的变量名

actions.getVariable('mode')
# 将 mode 替换为你想使用的变量名

这里存在一个细微差别:getVariable 读取的是当前快照,因此必须先 setVariablegetVariable 才能立即拿到新值——这正是官方示例采用“连续两行”写法的原因。

设置页面级变量

actions.setPageVariable('version', 1)
# 将 version 替换为你想使用的变量名

设置页面级变量后立即读取

actions.setPageVariable('number', 1)
# 将 number 替换为你想使用的变量名

actions.getPageVariable('number')
# 将 number 替换为你想使用的变量名

页面变量与普通变量的差异在于作用域:页面变量只在当前页面内可见,适合存放随页面生命周期的状态;普通变量作用于整个应用。关于变量体系的完整说明可参考 variables.md 概念文档

六、使用 Python 编写数据转换(Transformations)

Run Python Code 最常见的生产用途是作为查询的 Transformations(数据转换):在 Query Editor 中启用 Transformations 开关后,Python 代码会把查询返回的数据(固定以变量名 data 暴露)加工后返回给下游组件。

下面用一个 REST API 示例走一遍完整流程:

  1. 新建一条 REST API 查询,Method 保持默认的 GET
  2. URL 属性中填入测试接口地址:
https://dummyjson.com/products
  1. 点击 Run 按钮,在预览区查看返回的数据结构,大致如下:
products_data = {
    "products": [
        {"title": "iPhone 9", ...},
        {"title": "iPhone X", ...},
        # Additional products...
    ]
}

随后,基于这套数据,Enable Transformations 即可写出下面三类典型场景代码。

场景一:从响应中过滤出标题列表

遍历 products 列表并抽取每个商品的 title

return [product["title"] for product in data["products"]]

场景二:按分类过滤商品并输出标题

只保留分类为 smartphones 的商品标题:

return [product["title"] for product in data["products"] if product["category"] == "smartphones"]

场景三:计算某分类的平均价格

计算 laptops 分类下的平均价格,并处理“该分类为空”的边缘情况(返回 0):

return sum(product["price"] for product in data["products"] if product["category"] == "laptops") / len([product for product in data["products"] if product["category"] == "laptops"]) if len([product for product in data["products"] if product["category"] == "laptops"]) > 0 else 0

三个例子由浅入深地展示了同一个要点:Transformations 中的 Python 以 data 作为输入,以 return 的表达式作为输出,写法与普通的纯函数完全一致。因此无论是简单的字段抽取、条件过滤,还是聚合计算,Python 的标准语法都能直接胜任。

七、在组件中引用 Python 查询的返回数据

Run Python Code 查询与其他查询一样,其结果会挂载到全局查询对象上,可用双花括号表达式 {{ }} 绑定到任意组件属性。

例如你有一条名为 updatedProductInfo 的 Run Python Code 查询,希望在 Table 组件中渲染它返回的数据,只需在 Table 的 Data 属性中填入:

{{queries.updatedProductInfo.data}}

运行应用后,Table 就会以 Python 查询的返回结果(列表或对象数组)作为数据源自动渲染。这也印证了一个结论:Run Python Code 在 ToolJet 中并非“一次性脚本”,而是一条可复用的数据查询,其结果同样遵循 queries.<name>.data 的引用约定,可被表格、图表、文本等组件消费。

八、限制与避坑指南

Run Python Code 并非完整的服务器端 Python 环境,以下几点务必在使用前了解:

  1. 仅支持 Python 标准库:当前 runpy 运行时不提供第三方包(如 requestspandas 等),可用的只是 Python 标准库中的模块。官方文档在 run-py.md 中明确提示了这一点。

  2. 网络能力受限:由于 Python 基于浏览器端的 Pyodide 运行,使用标准库 urllib/urlopen 打开外部 URL 时可能失败。例如尝试访问 https://api.baserow.io 这类公网地址会报错,这与 Pyodide 的网络约束有关。完整的已知问题与排查请查阅 runpy-limits.md 故障排查文档

  3. 用 JS 互操作绕开网络限制:Pyodide 支持 Python ↔ JavaScript 互操作,可借助 from js import fetch 发起 HTTP 请求。以下是向外部 API 推送 JSON 数据的官方推荐写法:

from js import fetch
import json

async def push_data(url, data):
    response = await fetch(
        url,
        method='POST',
        headers=[
            ["Authorization", "Token <my_token>"],
            ["Content-Type", "application/json"]
        ],
        body=data
    )
    reply = await response.json()
    return reply

url = "https://api.baserow.io/api/database/rows/table/.../?user_field_names=true"
reply = await push_data(url, json.dumps(<my_data>))
reply

上面通过 fetch 发起 POST 请求,在 Authorization 头中携带令牌,以 JSON 作为请求体。也就是说:当标准库网络能力不够时,通过 js 桥接层调用浏览器的 fetch 即可。需要注意的是,发送前请确保自己拥有对应的鉴权令牌与合法的目标数据。

  1. 代码运行在浏览器本地:执行不占用服务器资源,但也意味着逻辑无法访问服务器端文件、环境变量或私有网络,所有“数据来源”都应是页面上下文中能被浏览器访问到的内容。

九、小结:何时选择 Run Python Code

与 JavaScript 版的 Run JavaScript(runjs) 数据源互为补充,Run Python Code 适合以下场景:

  • 团队更熟悉 Python,希望用 Python 语法完成组件交互与查询编排;
  • 需要把多行、可读性强的算法逻辑(字符串处理、循环、类封装)放进查询而不是一行表达式;
  • 在 Transformations 中对 API 响应做复杂的过滤、聚合与转换;
  • 希望先 await 一个查询完成、拿到 getData()/getRawData()/getLoadingState() 后再继续的时序敏感逻辑。

它会将结果挂载到 queries.<名称>.data 供组件引用,可无缝融入现有的事件流与数据绑定体系。参考源码:编辑器 UI 位于 Runpy.jsx,Pyodide 加载逻辑位于 _helpers/utils.jsrunpy 静态数据源类型定义可参见 server 端常量数据类型声明。遇到 urlopen 等网络相关报错时,直接查阅 RunPy 限制说明 即可对症解决。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391