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

PyScript加载外部Python脚本时函数无法被HTML按钮识别(Django环境)

问题描述

我编写了一个包含绘图逻辑与current_time函数的Python脚本:

import matplotlib.pyplot as plt
import numpy as np
from pyscript import Element
import datetime

x = np.random.randn(1000)
y = np.random.randn(1000)
fig, ax = plt.subplots()
ax.scatter(x, y)
display(fig, target="plot")


def current_time():
    now = datetime.datetime.now()

    # 获取指定id的段落元素
    paragraph = Element("current-time")

    # 向段落写入当前时间
    paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S"))

在Django环境中,我通过<py-script src="{% static 'py/script.py' %}"></py-script>将该脚本加载到HTML中,脚本的绘图功能可正常执行,但HTML按钮的py-click="current_time()"触发时会提示NameError: name 'current_time' is not defined;若将current_time函数直接嵌入HTML的<py-script>标签内,按钮则能正常调用函数。

外部脚本加载场景(报错)

{% extends "proj/base.html" %}
{% load static %}

{% block head %}
<link rel="stylesheet"
      href="https://pyscript.net/latest/pyscript.css"/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>

<py-config type="toml">
    packages = ["numpy", "matplotlib"]
</py-config>
{% endblock head %}

{% block content %}
<div id="plot"></div>
<button py-click="current_time()" id="get-time" class="py-button">获取当前时间</button>
<p id="current-time"></p>
{% endblock content %}

{% block script %}
<py-script src="{% static 'py/script.py' %}"></py-script>
{% endblock script %}

函数嵌入HTML标签场景(正常工作)

{% extends "proj/base.html" %}
{% load static %}

{% block head %}
<link rel="stylesheet"
      href="https://pyscript.net/latest/pyscript.css"/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>

<py-config type="toml">
    packages = ["numpy", "matplotlib"]
</py-config>
{% endblock head %}

{% block content %}
<div id="plot"></div>
<button py-click="current_time()" id="get-time" class="py-button">获取当前时间</button>
<p id="current-time"></p>
<py-script>
import datetime
def current_time():
    now = datetime.datetime.now()

    # 获取指定id的段落元素
    paragraph = Element("current-time")

    # 向段落写入当前时间
    paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S"))
</py-script>
{% endblock content %}

{% block script %}
<py-script src="{% static 'py/script.py' %}"></py-script>
{% endblock script %}

基础模板代码

{% load static %}
<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>{{ title }}</title>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"
          rel="stylesheet"
          integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi"
          crossorigin="anonymous">

    <!-- 自定义样式 -->
    <link href="{% static 'css/proj.css' %}" rel="stylesheet">
    <link href="{% static 'css/forms.css' %}" rel="stylesheet">
    <!-- 头部扩展块 -->
    {% block head %}{% endblock %}
</head>
<body>


<main class="d-flex flex-nowrap">

    {% include 'proj/navbar.html' %}

    <div class="b-example-divider b-example-vr"></div>

    <div class="content">
        {% block content %}{% endblock %}
    </div>

</main>

<!-- 脚本扩展块 -->
{% block script %}{% endblock %}

<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"
        integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js"
        integrity="sha384-IDwe1+LCz02ROU9k972gdyvl+AESN10+x7tBKgc9I5HFtuNz0wWnPclzo6p9vxnk"
        crossorigin="anonymous"></script>
</body>
</html>
原因分析

这是PyScript的作用域机制导致的:

  • 内联<py-script>标签中定义的函数,默认会被加入全局PyScript命名空间,HTML元素的py-click等属性可以直接访问这个命名空间的内容。
  • 通过src加载的外部脚本,默认运行在独立的模块作用域中,内部定义的函数不会自动暴露到全局命名空间,因此HTML按钮无法找到current_time函数。
解决方案

要让外部脚本的函数能被py-click调用,需要手动将函数暴露到全局命名空间,有两种常用方法:

方法1:挂载函数到pyscript.window

修改外部脚本script.py,将current_time函数挂载到全局window对象:

import matplotlib.pyplot as plt
import numpy as np
from pyscript import Element, window
import datetime

# 绘图逻辑保持不变
x = np.random.randn(1000)
y = np.random.randn(1000)
fig, ax = plt.subplots()
ax.scatter(x, y)
display(fig, target="plot")


def current_time():
    now = datetime.datetime.now()
    paragraph = Element("current-time")
    paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S"))

# 将函数挂载到全局window对象
window.current_time = current_time

方法2:使用@pyscript.expose装饰器

PyScript提供的expose装饰器可以直接将函数暴露到全局命名空间:

import matplotlib.pyplot as plt
import numpy as np
from pyscript import Element, expose
import datetime

# 绘图逻辑保持不变
x = np.random.randn(1000)
y = np.random.randn(1000)
fig, ax = plt.subplots()
ax.scatter(x, y)
display(fig, target="plot")

# 用装饰器暴露函数
@expose
def current_time():
    now = datetime.datetime.now()
    paragraph = Element("current-time")
    paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S"))

修改完成后,外部脚本中的current_time函数就能被py-click="current_time()"正常调用了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 20:57:02