在 Flask-Admin 的内置模板中添加填充其他字段的按钮
add buttons that populate other fields in built-in templates of Flask-Admin
我想在我的 Flask-Admin 创建视图中添加一个按钮,在 this question 之后,我成功地做到了。
现在,假设模型传递给那个视图,比如说 User
有:
- 与
ClassA
和ClassB
的一对多关系
ClassA
与 ClassB
也有 一对多 关系
假设在我的创建视图中,我在创建 User
的实例时添加了一些 ClassA
的实例,比如说 my_class_a_instance
,我想要这个按钮:
- 对
my_class_a_instance
执行查询,返回当时与之相关的 ClassB
(或 my_class_b_instance
s)的所有实例
- 使用这些结果填充创建模板中的
form.class_b
字段
- 如果可能,弹出一些模式 window 提示用户进行确认。
可能
到目前为止,我的方法是这样的:
# 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 %}-
我会像文档中所说的那样注册这个视图
# admin/views.py
class CascadesView(ModelView):
create_template = 'admin/cascade_button_create.html'
我还没有找到这方面的信息,而且模板中没有很多有用的评论。
谢谢!
编辑:
我已经从 flask-admin
存储库中复制了示例,并在 https://github.com/diegoquintanav/flask-admin-autopopulate 中设置了我的示例以供使用
我进一步研究了一下,这似乎是非常具体的行为,并没有在 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>
以及处理这个请求的 flask 路由:
@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))
它似乎工作得很好,并且可以处理大多数边缘情况(我希望如此)。
我想在我的 Flask-Admin 创建视图中添加一个按钮,在 this question 之后,我成功地做到了。
现在,假设模型传递给那个视图,比如说 User
有:
- 与
ClassA
和ClassB
的一对多关系
ClassA
与ClassB
也有 一对多 关系
假设在我的创建视图中,我在创建 User
的实例时添加了一些 ClassA
的实例,比如说 my_class_a_instance
,我想要这个按钮:
- 对
my_class_a_instance
执行查询,返回当时与之相关的ClassB
(或my_class_b_instance
s)的所有实例 - 使用这些结果填充创建模板中的
form.class_b
字段 - 如果可能,弹出一些模式 window 提示用户进行确认。
到目前为止,我的方法是这样的:
# 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 %}-
我会像文档中所说的那样注册这个视图
# admin/views.py
class CascadesView(ModelView):
create_template = 'admin/cascade_button_create.html'
我还没有找到这方面的信息,而且模板中没有很多有用的评论。
谢谢!
编辑:
我已经从 flask-admin
存储库中复制了示例,并在 https://github.com/diegoquintanav/flask-admin-autopopulate 中设置了我的示例以供使用
我进一步研究了一下,这似乎是非常具体的行为,并没有在 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>
以及处理这个请求的 flask 路由:
@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))
它似乎工作得很好,并且可以处理大多数边缘情况(我希望如此)。