使用AJAX进行Flask flash和url_for

时间:2014-06-18 14:35:32

标签: javascript python ajax flask jinja2

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

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

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

我遇到过两个问题:

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

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

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

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

<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调用正确的方法来编辑客户端。我的方法如下:

@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。

我想要这个:

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

成为这个:

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变化非常灵活。

感谢。

4 个答案:

答案 0 :(得分:3)

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

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

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)
    }
})

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

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”等网址进行编辑。

答案 1 :(得分:1)

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

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

<div id="flash"></div>

你的ajax电话:

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

并使用解析功能:

var flashMessage = function(data){
  html = '';
  for (i=0; i<data.length; i++) {
    html += '<div class="alert alert-' + data[i]['type'] + '"><a href="#" class="close" data-dismiss="alert">&times;</a>' + data[i].message + '</div>';
  }
  return html;
};

在处理AJAX请求的路由中,只需返回一个类似于:

的JSON对象

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

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

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

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

此外,如果您不需要多条Flash消息,只需更换“追加”即可。用&#39; html&#39;

答案 2 :(得分:0)

你可以写一个简单的javascript方法来取代烧瓶的功能&#39; flash&#39;通过了解flash_message.html的格式化方法。

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';      
   $('<div class="alert alert-'+category+'"><i class="'+icon+'"></i>&nbsp;<a class="close" data-dismiss="alert">×</a>'+ message +'</div>').prependTo('#maincontent').hide().slideDown();
   $.smoothScroll({
     scrollElement: $('body'),
     scrollTarget: '#mainContent'
   });
}

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

答案 3 :(得分:0)

一个非常老的问题,但是我遇到了同样的问题,并且找到了一种通过ajax获取烧瓶闪烁的变通方法。基本上,我所做的是我创建了一条get_flashes路由,该路由返回flashes模板,并且正在通过jQuery的load函数使用该路由。 $('#msg-div').load('{{ url_for('main.get_flashes') }}'

get_flashes路线:

@main.route('get-flashes')
def get_flashes():
    return render_template('_flashes.html')

_flashes.html(获取闪光的模板,请参见flask's docs中的更多信息)

{%- with messages = get_flashed_messages(with_categories=true) -%}
    {% if messages %}
        {% for category, message in messages %}
            {% if category == 'error' %}
            <div class="alert alert-danger alert-dismissable fade show msg" role="alert">
                {{ message }}
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            {% else %}
            <div class="alert alert-{{ category }} alert-dismissable fade show msg" role="alert">
                {{ message }}
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            {% endif %}
        {% endfor %}
    {% endif %}
{%- endwith %}