【问题标题】:Saving HandsOnTable data with Flask使用 Flask 保存 HandsOnTable 数据
【发布时间】:2015-07-14 11:13:16
【问题描述】:

我正在尝试使用 Flask 从HandsOnTable 加载和保存数据。我正在关注 these instructions 使用 ajax 加载和保存(检索和发送)数据。我已经设法从返回 JSON 字典的 URL 将数据加载到表中,但我还没有弄清楚如何发送数据并存储在我的数据库中。

以下是 javascript 的相关部分:

Handsontable.Dom.addEvent(save, 'click', function() {
    // save all cell's data
    ajax('/json/save.json', 'GET', JSON.stringify({data: hot.getData()}), function (res) {
      var response = JSON.parse(res.response);

      if (response.result === 'ok') {
        exampleConsole.innerText = 'Data saved';
      }
      else {
        exampleConsole.innerText = 'Save error';
      }
    });
  });

希望这是从 HandsOnTable 中获取数据,将其转换为这种格式的大型 JSON 表:

{'data' : [[row 1], [row 2],...]}

下面是相关的 Flask 视图函数的样子:

@app.route('/json/save.json', methods = ['GET', 'POST'])
@login_required
def jsonSave():
    data = request.form['data']
    #Do stuff to load data into database
    return 'ok'

删除了不相关的部分。基本上我的问题是如何使保存功能的data = request.form['data'] 部分工作,并将其变成一个简单的行列表?

顺便说一句,这很困难的部分原因是我无法看到通过 ajax 调用发送到视图函数的确切内容。有没有办法让我可以更轻松地调试这样的问题?打印语句似乎在视图函数中不起作用(我在控制台中看不到它们)。

非常感谢, 亚历克斯

更新(再次)按照 ZekeDroid 的说明更改为:

Handsontable.Dom.addEvent(save, 'click', function() {
// save all cell's data
console.log(JSON.stringify({data: hot.getData()}));
ajax('/json/save/{{well['id']}}', 'POST', JSON.stringify({data: hot.getData()}), function (res) {
  var response = JSON.parse(res.response);

  if (response.result === 'ok') {
    exampleConsole.innerText = 'Data saved';
  }
  else {
    exampleConsole.innerText = 'Save error';
  }
});

});

@app.route('/json/save/<int:well_id>', methods = ['GET', 'POST'])
@login_required
def jsonSave(well_id):
    jsonData = request.get_json()
    print 'jsonData:', jsonData
    data = jsonData['data']
    print 'data:', data
    #Insert table into database
    print 'saving', well_id
    return json.dumps(True)

调试输出: 基本上,看起来 Flask 在调用jsonData = request.get_json() 时没有加载 json 对象。不过,console.log(JSON.stringify({data: hot.getData()})); 看起来还不错。

这是浏览器和 Flask 控制台的输出:

浏览器:

{"data":[["01/01/15",100,300,200,96],["01/02/15",200,500,300,50],["01/03/15",300,600,400,80],["01/01/15",100,300,200,96],["01/02/15",200,500,300,50],["01/03/15",300,600,400,80],["01/01/15",100,300,200,96],["01/02/15",200,500,300,50],["01/03/15",300,600,400,80],[null,null,null,null,null]]}
samples.js:94 POST http://127.0.0.1:5000/json/save/1 500 (INTERNAL SERVER ERROR)

烧瓶:

jsonData: None
127.0.0.1 - - [13/May/2015 11:41:31] "POST /json/save/1 HTTP/1.1" 500 -
Traceback (most recent call last):
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1817, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask\app.py", line
1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\aschmitt\Envs\PetroTools\lib\site-packages\flask_login.py", lin
e 758, in decorated_view
    return func(*args, **kwargs)
  File "C:\Users\aschmitt\Dropbox\Python\PetroTools\app\views.py", line 236, in
jsonSave
    data = jsonData['data']
TypeError: 'NoneType' object has no attribute '__getitem__'

【问题讨论】:

    标签: javascript flask handsontable


    【解决方案1】:

    这是一个很好的问题,到目前为止做得很好!现在,让我们从显而易见的开始。您正在使用 GET 请求向 Flask 发送数据,但您实际上是在尝试 POST 数据,这就是 Python 在 request 中没有任何内容的原因。如果我错了,请纠正我,因为情况可能并非如此,但这是您调试它的方式:

    您应该在某处的外壳上运行烧瓶。在这里您将看到任何print 语句,因此,在jsonSave() 中,在您定义它之后添加行print data。此外,您错误地检索数据有两个原因。首先语法如下:

    jsonData = request.get_json()
    data = jsonData["data"]
    

    此外,如果您期待状态响应,则使用 JSON 和布尔值响应可能是值得的:

    return json.dumps(True)
    

    现在是前端。在将数据发送到服务器之前,只需将其打印到控制台即可。在ajax 调用的正上方添加这一行:

    console.log(JSON.stringify({data: hot.getData()}));
    

    这应该足以让您调试双方。在看到这一点并进行更改后,我建议您应该更好地了解问题所在,但如果没有,请使用您认为相关的输出更新您的问题(例如,如果 python 在尝试打印 @ 时打印空行987654332@).

    编辑:

    能够以您设置路线的方式接收参数是不正确的。还有为什么你有save.json?相反,试试这个:

    @app.route('/json/save/<well_id>', methods = ['GET', 'POST'])
    @login_required
    def jsonSave(well_id):
        jsonData = request.get_json()
        data = jsonData['data'] # this will fail if it is not a POST request
        print 'data:', data
        #Do stuff to load data into Database
        print 'saving', well_id
        return json.dumps(True)
    

    在你的 ajax 调用中:

    ajax('/json/save/{{well['id']}}', 'POST', JSON.stringify({data: hot.getData()}), function (res) {})
    

    另外,请发布控制台日志和打印语句。我们在这里仍然处于黑暗之中。

    【讨论】:

    • 非常感谢。我已经进行了您的更改,但我仍然做错了什么。当我第一次加载页面时,它给了我两个错误,GET http://127.0.0.1:5000/index.html 404 (NOT FOUND)Uncaught TypeError: Cannot read property 'querySelectorAll' of null。当我尝试保存数据时,它显示GET http://127.0.0.1:5000/json/save.json/1 500 (INTERNAL SERVER ERROR)Uncaught SyntaxError: Unexpected token &lt;。这是否与我从旧版本的 HandsOnTable 网站复制的 samples.js 文件有关,因为它不再托管在那里?
    • 我使用this jsFiddle 作为参考点,您可以在那里看到它包括&lt;script src="http://handsontable.com/demo/js/samples.js"&gt;&lt;/script&gt;。该文件不再存在,但我从回来的机器上得到了一个存档版本并使用了它。不确定这是否是某些问题的根源?
    • 好吧,让我们看看。首先,从更新的问题来看,您做错了两件事。一是您的 ajax 调用仍在执行 GET 请求,因此第三个参数被忽略,二是在您的 Flask 代码中您实际上没有获得任何参数,请参阅我更新的响应。
    • 第一个错误 404 是 Fl​​ask 错误。你做错了什么,因为没有'/index.html'的路线。 querySelectorAll 错误我不知道,因为我在您的代码中没有看到您正在使用它的任何地方。
    • 嗯好的。我在问题中添加了控制台输出。基本上看起来jsonData 设置为 None 会导致函数失败。
    【解决方案2】:

    为了解决这个问题,我重新开始。我包含了这些 javascript 文件:

    <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
    <link rel="stylesheet" media="screen" href="http://handsontable.com/dist/handsontable.full.css">
    <script src="http://handsontable.com/dist/handsontable.full.js"></script>
    

    我删除了从旧 jsfiddle 获得的 samples.js 文件。我认为这是把事情搞砸了。

    根据 ZekeDroid 的建议,我将烧瓶保存功能更改为:

    @app.route('/json/save/<int:well_id>', methods = ['GET', 'POST'])
    @login_required
    def jsonSave(well_id):
        w = Well.query.get(well_id)
        jsonData = request.get_json()
        print 'jsonData:', jsonData
        data = jsonData['data']
        print 'data:', data
    
        #Load Data dictionary into the database.
    
        return json.dumps(True)
    

    我用这个替换了 jquery 保存功能:

    Handsontable.Dom.addEvent(save, 'click', function() {
        // save all cell's data
        var arr = { data: hot.getData()};
        $.ajax({
        url: '/json/save/{{well['id']}}',
        type: 'POST',
        data: JSON.stringify(arr),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        async: true,
        success: function(msg) {
            console.log(msg);
          }
          });
    });
    

    我无法从实用教程 (here) 中获得保存功能,因此我使用了已接受的答案 here。我使用 POST 是因为如果我理解正确,它没有像 GET 那样的大小限制,而且我将发送一些相当大的数组。

    删除samples.js 文件也破坏了加载功能,因此我将其替换为:

    Handsontable.Dom.addEvent(load, 'click', function() {
        var arr = { data: []};
        $.ajax({
        url: '/json/load/{{well['id']}}',
        type: 'GET',
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify(arr),    
        dataType: 'json',
        async: true,
        success: function(msg) {
            hot.loadData(msg.data);
            console.log('Loaded:');
            console.log(msg.data);
        }
        });
    });
    

    这显然与保存功能非常相似。感谢 ZekeDroid 的所有帮助。

    亚历克斯

    【讨论】:

      猜你喜欢
      • 2013-11-29
      • 2017-05-10
      • 2013-08-11
      • 2013-04-24
      • 2012-11-01
      • 2016-02-24
      • 2014-02-01
      • 2015-11-11
      • 2013-10-31
      相关资源
      最近更新 更多