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 += '×' + data[i].message + ''; } return html; }; |
在处理AJAX请求的路由中,只需返回一个如下所示的JSON对象:
其中'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可能有点棘手,但可能。