【发布时间】:2019-10-21 23:46:10
【问题描述】:
总结
请参阅玩具示例 Azure 笔记本 hosted at this link。笔记本可以从那里克隆并运行,或下载并在本地运行,但为方便起见,所有代码也在下面。
当所有单元格运行时,javascript 控制台在最后一个单元格中报告这些错误(缩写),并且最终预期的输出行没有呈现:
Error: Could not create a view for model id 91700d0eb745433eaee98bca2d9f3fc8
at promiseRejection (utils.js:119)
Error: Could not create view
at promiseRejection (utils.js:119)
Uncaught (in promise) TypeError: Cannot read property 'then' of undefined
Uncaught (in promise) TypeError: Cannot read property 'then' of undefined
不知道哪里出错了。
更新:
由于它当前存在,代码将字符串实例(而不是DOMWidgetModel 实例)发送到create_child_view 方法。该字符串包含"IPY_MODEL_" 附加模型ID。这似乎可能是问题的根源。客户端正在从服务器端 Backbone children 模型数组项 (this.model.get('children')) 接收该字符串实例。
我想知道这个问题是否与low-level widget tutorial 中讨论的小部件的[反]序列化有关。但我不确定如何使用它来解决这个问题,因为我需要访问子小部件模型本身而不仅仅是属性。而且我相信我正确地传递了教程指定的**widgets.widget_serialization。
详情
笔记本包含 python 和 javascript 代码,并利用严重依赖 Backbone 的 ipywidgets 库。后端代码(python,cell #1)创建了一个ipywidgets.DOMWidget 子类小部件,Test(一个在前端镜像的 Backbone 模型)。前端代码(javascript,单元格#2)创建了一个ipywidgets.DOMWidgetView 子类TestView,它在呈现到页面时由小部件实例化。
Test 模型小部件有一个 children 成员,该成员由多个“子小部件”(也是模型)组成。这些小部件是 python 类Sub 的实例。当Test 的视图被渲染时,我想实例化和渲染子小部件的视图并将它们附加到父Test 小部件的视图(注意:最后部分尚未在下面实现)。
问题是当我尝试按照ipywidgets API 创建子视图时,通过在每个子模型上使用create_child_view 方法实例化子视图来填充ViewList 数组不起作用。
这类事情的 API 没有特别详细的文档,所以我尽我所能遵循各种类似的示例,说明如何使用父视图中的子模型(例如父小部件)实例化子视图in ipywidgets itself 和 in ipyleaflet。但我所做的一切似乎都无法让儿童视图的创建发挥作用。
请注意,我能够单独呈现每个Sub 小部件的视图,而不会出现任何问题。只有当我尝试使用create_child_view 方法从父Test 小部件中创建视图时,我们才会遇到问题。
代码
单元 1(服务器端 jupyter python 内核)
import ipywidgets.widgets as widgets
from traitlets import Unicode, List, Instance
from IPython.display import display
class Sub(widgets.DOMWidget):
"""Widget intended to be part of the view of another widget."""
_view_name = Unicode('SubView').tag(sync=True)
_view_module = Unicode('test').tag(sync=True)
_view_module_version = Unicode('0.1.0').tag(sync=True)
class Test(widgets.DOMWidget):
"""A parent widget intended to be made up of child widgets."""
_view_name = Unicode('TestView').tag(sync=True)
_view_module = Unicode('test').tag(sync=True)
_view_module_version = Unicode('0.1.0').tag(sync=True)
children = List(Instance(widgets.Widget)).tag(sync=True,
**widgets.widget_serialization)
def __init__(self, subs):
super().__init__()
self.children = list(subs)
Cell 2(前端 jupyter notebook 代码)
%%javascript
require.undef('test');
define('test', ["@jupyter-widgets/base"], function(widgets) {
var SubView = widgets.DOMWidgetView.extend({
initialize: function() {
console.log('init SubView');
SubView.__super__.initialize.apply(this, arguments);
},
render: function() {
this.el.textContent = "subview rendering";
},
});
var TestView = widgets.DOMWidgetView.extend({
initialize: function() {
console.log('init TestView');
TestView.__super__.initialize.apply(this, arguments);
this.views = new widgets.ViewList(this.add_view, null, this);
this.listenTo(this.model, 'change:children', function(model, value) {
this.views.update(value);
}, this);
console.log('init TestView complete');
},
add_view: function (child_model) {
// error occurs on this line:
return this.create_child_view(child_model);
},
render: function() {
this.views.update(this.model.get('children'));
this.el.textContent = 'rendered test_view';
},
});
return {
SubView : SubView,
TestView : TestView,
};
});
Cell 3(用于测试的python代码)
models=[Sub() for _ in range(4)]
for m in models:
# view each Sub object individually
display(m) # output: 'subview rendering'
t=Test(models)
t # output: 'rendered test_view' <-- broken; see console log
输出
当前输出:
subview rendering
subview rendering
subview rendering
subview rendering
预期输出:
subview rendering
subview rendering
subview rendering
subview rendering
rendered test_view
如果有人有兴趣,可以在this github issue 获取有关我正在从事的实际项目的更多具体信息。
【问题讨论】:
-
你有任何图像,输出应该是什么样子?
-
@ASHu2 我在笔记本中添加了预期的输出(和一些注释),希望对您有所帮助。
-
@ASHu2 每个单独的子视图本身的“子视图渲染”是预期的并且可以正常工作。来自:
for m in models: display(m)。在 parent 对象中添加新视图时会发生错误,使用this.create_child_view(child_model). -
谢谢。如果大多数输出都是
none,您能否检查t.get_manager_state()? -
@ASHu2 Link
标签: javascript python backbone.js jupyter-notebook ipywidgets