在Flask Admin的内置模板中添加填充其他字段的按钮

在Flask Admin的内置模板中添加填充其他字段的按钮,flask,flask-admin,Flask,Flask Admin,我想在我的Flask Admin创建视图中添加一个按钮,下面我设法做到了这一点 现在,假设传递给该视图的模型,例如User具有: 与ClassA和ClassB ClassA与ClassB 假设在我的创建视图中,我在创建User的实例时添加了ClassA的某个实例,比如说my_class\u a\u实例,我希望此按钮: 对my_class\u a_实例执行查询,返回当时与其相关的ClassB(或my_class\u b_实例s)的任何实例 用这些结果填充创建模板中的表单.class_b字段

我想在我的Flask Admin创建视图中添加一个按钮,下面我设法做到了这一点

现在,假设传递给该视图的模型,例如
User
具有:

  • ClassA
    ClassB
  • ClassA
    ClassB
假设在我的创建视图中,我在创建
User
的实例时添加了
ClassA
的某个实例,比如说
my_class\u a\u实例
,我希望此按钮:

  • my_class\u a_实例
    执行查询,返回当时与其相关的
    ClassB
    (或
    my_class\u b_实例
    s)的任何实例
  • 用这些结果填充创建模板中的
    表单.class_b
    字段
  • 如果可能,弹出一些模式窗口提示用户确认。有可能
到目前为止,我的方法是:

# templates/admin/cascade_button_create.html

{% extends 'admin/model/create.html' %}

{% block body %}

{% call lib.form_tag(form) %}
<div class="row">
  <div class="col-xg-10">
    {{ lib.render_form_fields([form.name])}}
  </div>
</div>

<div class="row">
    <div class="col-xg-10">
        <!-- form.cities follows the attributes of sqla model -->
      {{ lib.render_form_fields([form.instances_of_a])}}
    </div>
    <div class="col-xg-2">
        <!-- so this button should query any model related to form.cities 
        and populate the create form with whatever comes out.

        Say Street has a one to many relationship, I want this 
        button to run some method of the form get_instances_of_b_from_instance_of_a(form.instances_of_a) (query_method() for short) that fills
        the field form.instances_of_b

        If possible I would like to pop up a modal window prompting the user
        to confirm this before filling this field.-->
      <a href="{{ query_method() }}" class="btn btn-default">Add with cascade</a>
    </div>
</div>


<div class="form-buttons">
  {{ lib.render_form_buttons(return_url) }}
</div>
{% endcall %}
{% endblock %}-
我还没有找到这方面的信息,模板也没有很多有用的注释

谢谢

编辑:


我复制了flask adminrepo中的示例,并将我的示例设置为使用

我进一步研究了它,这似乎是非常具体的行为,在flask admin中没有实现。我继续看了一下,我能想到的唯一简单的方法就是使用Ajax和一个特殊的api路由

因此,我已将此添加到您的js中:

<a href="#" class="btn btn-default" onClick="retrieve_location_b_ids()">Add with cascade</a>
<script>
function retrieve_location_b_ids(){

  // make sure that the user wants to preload the b locations
  if (confirm('load location b connected to location a?')){
    // look for the selected options
    var selected_a_locations = $('#s2id_sub_locations_a').select2("val");

    // request the b_ids using the a_ids provided by the user using ajax
    var oData = new FormData();
    oData.append('selected_a_locations', JSON.stringify(selected_a_locations));
    var oReq = new XMLHttpRequest();
    oReq.open("POST", "{{url_for('look_up_b_locations_connected_to_a_locations')}}", true);
    oReq.onload = function(oEvent) {
      if (oReq.status == 200) {
        // get the correct b ids back from the ajax request, and use them to load the select2 field
        var selected_b_ids_list = JSON.parse(oReq.responseText)
        $('#s2id_sub_locations_b').select2('val', selected_b_ids_list);
      } else {
        alert("Error " + oReq.status + " occurred when retrieving the ids")
      }
    };
    oReq.send(oData);
  }
}

</script>

它似乎工作得很好,可以处理大多数边缘情况(我希望如此)

我想你应该先看看这本书。如果你愿意,在github上或这里放一个完整的最小示例,我会试一试,因为我认为这是一个有趣的问题。目前我没有最小示例,对不起。我无法使它工作。我将尝试您提到的内容,并期望稍后再提供一个更好的示例。该示例现在适用于Flask Admin repo的引导示例,如我作为参考发布的SO问题所示,它只显示一个不起任何作用的按钮。@Joost如果您想试一试,我已经添加了一个repo。我也会努力的。这很有效!我唯一不明白的一行是
var selected_a_locations=$('s2id_sub_locations_a')。select2(“val”)这是的特定语法吗?如果是这样的话,
#s2id\u sub\u a
指的是什么?是的,它是select2语法。我还得查一下,因为我以前从未听说过
#s2id_sub_locations_a
是管理员在DOM中为字段提供的id。您需要此id,以便找出所选的值。通过在浏览器中使用inspect元素,我发现这是一个特定的值。这确实是一个相当特定的行为。再次感谢!我已经评论了你的公关,所以请检查一下。
<a href="#" class="btn btn-default" onClick="retrieve_location_b_ids()">Add with cascade</a>
<script>
function retrieve_location_b_ids(){

  // make sure that the user wants to preload the b locations
  if (confirm('load location b connected to location a?')){
    // look for the selected options
    var selected_a_locations = $('#s2id_sub_locations_a').select2("val");

    // request the b_ids using the a_ids provided by the user using ajax
    var oData = new FormData();
    oData.append('selected_a_locations', JSON.stringify(selected_a_locations));
    var oReq = new XMLHttpRequest();
    oReq.open("POST", "{{url_for('look_up_b_locations_connected_to_a_locations')}}", true);
    oReq.onload = function(oEvent) {
      if (oReq.status == 200) {
        // get the correct b ids back from the ajax request, and use them to load the select2 field
        var selected_b_ids_list = JSON.parse(oReq.responseText)
        $('#s2id_sub_locations_b').select2('val', selected_b_ids_list);
      } else {
        alert("Error " + oReq.status + " occurred when retrieving the ids")
      }
    };
    oReq.send(oData);
  }
}

</script>
@app.route('/api/look_up_b_locations_connected_to_a_locations', methods=['POST'])
def look_up_b_locations_connected_to_a_locations():
    # use a set in case the same b location is in multiple a locations to prevent duplicates
    b_location_set = set()
    a_location_list = json.loads(request.form['selected_a_locations'])
    for a_location_id in a_location_list:
        a_location = SubLocationA.query.get_or_404(a_location_id)
        for b_location in a_location.sub_sub_locations_b:
            b_location_set.add(str(b_location.id))
    return jsonify(list(b_location_set))