关于javascript:使用AJAX的Flask flash和url_for

Flask flash and url_for with AJAX

我目前陷入了一个相当"大"的问题,我会尽可能地清楚简明。
我正在使用Flask开发Python工具。它意味着是一个内联网。我的想法是我有一个客户页面。有它的名字,许多其他信息,以及一个庞大的清单。

信息已经写入输入字段,因此用户只需在那里编辑它们,按回车键,页面将重新加载编辑的信息(通知,使用闪烁的消息和咆哮)。
大量的清单迫使我转移到使用AJAX的系统,因为我希望它在用户勾选框并在输入中输入内容时"实时"更新,而无需重新加载页面。

因此,我也将我对信息的基本输入切换为AJAX,以便重新加载法师。

我遇到过两个问题:

第一个涉及Flask的消息闪烁功能。我有一个方法更新数据库中的客户端名称,闪烁消息(成功或失败,取决于许多事情),然后再次显示页面。为了避免页面重新加载,我正在使用AJAX管理表单提交。

问题是,我的python方法会闪烁消息。一旦我回到我的html页面(由于它是AJAX),它还没有重新加载,因此Jinja2的get_flashed_message函数没有返回任何内容,因为它尚未更新。因此,我无法检索那些闪烁的消息。

我怎么能得到这些?我看到的唯一解决方案是摆脱任何flash的使用,并编写我自己的消息système,我将从方法返回,然后在javascript中处理。这看起来非常愚蠢,因为Flash是Flask的一个功能,它被AJAX"无用"了?我觉得我错过了什么。
(作为一个注释,到目前为止,我的闪存消息管理是在我的基本布局中进行的,它调用一个贯穿所有消息的模板并将其显示为咆哮通知)

第二个问题涉及url_for。这是我的表单,用于编辑客户端的名称:

1
2
3
4
<form id="changeClientName" method="POST" action="{{ url_for('clients.edit_client_name', name=client.name) }}" style="display:inline !important;">
    <input type="text" name="name" class="form-control" value="{{ client.name }}">
    <input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;"/>
</form>

如您所见,action属性使用url_for调用正确的方法来编辑客户端。我的方法看起来像这样:

1
2
@mod.route('/edit/<name>/', methods=['POST'])
def edit_client_name(name):

所以url路径是/ edit / the_client_name。因此,在编辑之后,如果我们要重新编辑此名称,则新URL为/ edit / the_new_client_name。
显然,一旦调用了该方法,我的AJAX必须更改此操作属性,将其替换为新URL(如果用户想要重新编辑名称而不更改页面/重新加载页面)。这是我的第二个问题。

新名称存储在javascript中。行动仍然是旧的网址。所以我必须使用新名称调用url_for。我发现绝对没有办法将Javascript变量传递给Jinja2。

我要这个 :

1
url_for('clients.edit_client_name', name=client.name)

成为这样:

1
url_for('clients.edit_client_name', name=my_javascript_variable_one_way_or_another)

我只需要调用修改表单属性的js函数,并使用这个新的url_for修改我的action属性。但是我发现没有办法做出这个简单的事情,即给Jinja2一个javascript变量,看起来好像我不太可能。

所以这是我的两个问题。如何使Flash与AJAX兼容?我怎样才能将javascript属性传递给Jinja2?

我真诚地希望找到这两个"愚蠢"问题的解决方案。我能看到的唯一解决方案就是编写我自己的消息传递系统,它会破坏flash的目标,使得AJAX无用,这看起来很愚蠢,并且在我的模板中对URL进行硬编码,这完全违背了Flask制作的最初兴趣来自方法的URL独立,并且URL更改非常灵活。

谢谢。


我会抓住这个,但我不确定我完全理解这个问题:D。下面的代码没有经过测试,它更像伪代码!

您的第一个问题是(如果我理解正确的话)您正在通过ajax进行部分更新,并希望在部分更新之后获取更新结果。您不应在以后获取更新结果,而应在每次ajax调用后返回它们。因此,如果您有更新代码,如下所示:

1
2
3
4
5
6
7
8
9
data = $('#my-form').serialize()
$.post(update_url, data, function (results) {
    // Here you check results.
    if (results.success) {
        $('#update-div').message('Update Success')
    } else {
        $('#update-div').message('Update Failed: ' + results.error_msg)
    }
})

然后您的更新路由将具有类似于此的代码:

1
2
3
4
5
6
7
8
9
from flask import jsonify

@app.route('/partialupdate/<int:userid>', methods=['POST'])
def partial_update(userid):
    try:
        # fetch the user, perform the updates and commit
        return jsonify(success=1)
    except Exception, e:
        return jsonify(success=0, error_msg=str(e))

您可以使用USERID而不是客户端名称修复涉及URL生成的第二个问题。切勿将客户名称用于搜索以外的任何内容:D。在这种情况下使用用户ID。用户标识通常是数据库中特定用户的主键。如果您没有使用数据库,那么以某种方式生成您自己的用户ID并将其附加到用户 - 它应该是每个用户的唯一编号。使用用户ID意味着您始终可以使用"/ edituser / 1"等网址进行编辑。


我也有这个要求。为了充实Paul Wand的答案,我就是这样做的(请注意,生成的标记是针对bootstrap 3的:

为模板中的flash消息添加一个空div:

1
 

你的ajax电话:

1
2
3
$.post("/foo/bar", JSON.stringify({'calls': 'whatever'}), function(returnedData) {
    $('#flash').append(flashMessage(JSON.parse(returnedData)));
});

并使用解析功能:

1
2
3
4
5
6
7
var flashMessage = function(data){
  html = '';
  for (i=0; i<data.length; i++) {
    html += '&times;' + data[i].message + '';
  }
  return html;
};

在处理AJAX请求的路由中,只需返回一个如下所示的JSON对象:

[{'type': 'success', 'message': 'Here is a message'}]

其中'type'是bootstrap 3状态类型,即。成功,信息,警告,危险。 dict包含在列表中,因此如果需要,您可以传递多个。

如果响应已经被jsonified,则不需要JSON.parse。在这种情况下,代码只是:

1
$('#flash').append(flashMessage(returnedData));

此外,如果您不需要多个Flash消息,只需将'append'替换为'html'


您可以通过了解flash_message.html的格式来编写一个简单的javascript方法来替换flask'flash'方法的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function flash(message,category){
   if (category == 'error'){
      var icon='icon-exclamation-sign';
      category='danger';
      }
   else if (category == 'success')
      var icon='icon-ok-sign';
   else
      var icon='icon-info-sign';      
   $('<i class="'+icon+'">×'+ message +'').prependTo('#maincontent').hide().slideDown();
   $.smoothScroll({
     scrollElement: $('body'),
     scrollTarget: '#mainContent'
   });
}

url_for可能有点棘手,但可能。