HTML范围滑块可通过AJAX调用到Flask [英] HTML range slider to Flask with AJAX call
问题描述
我有一个带有各种按钮和滑块的HTML控制面板.所有按钮都可操作,并且单击后会发送发布请求,我的Python应用程序会收到该请求,然后执行功能.
I have a HTML control panel with various buttons and sliders. All of the buttons are operational and when clicked send a post request which my Python app receives and then executes functions.
我似乎无法使滑块控件正常工作,调整滑块时出现以下错误:
I cannot seem to get the slider controls to work, When I adjust the slider I get the following error:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'button'
这是有希望的,因为至少我可以看到它尝试做某事而失败,这是迄今为止取得的最佳结果.我的JavaScript和AJAX知识有限,我需要一种解决方案,使滑块可以在python可以解释的任何onchange值上发布请求.
This is promising as at least I can see it trying to do something and failing, which is the best result achieved thus far. My javascript and AJAX knowledge is limited and I need a solution for the slider to POST request on any onchange value that python can then interpret.
我最初有以下HTML:
I initially had the following HTML:
<input id="slider" type="range" min="0" max="100" value="50" onchange="updateVolume(getElementById('slider').value); return false;">
JavaScript:
Javascript:
<script>
function updateVolume (vol) {
$.ajax({
method: "POST",
url: '{{ url_for('main.control_panel', video_id=video.id) }}',
data: { volume: vol}
})
.done(function( msg ) {
// optional callback stuff if needed
// alert( "Data Saved: " + msg );
});
}
</script>
这引发了同样的错误.
这是我当前的代码,也会引发相同的错误:
This is my current code that also throws the same error:
HTML:
<input id="slide" type="range" min="1" max="100" step="1" value="10" name="slide">
<div id="sliderAmount"></div>
JavaScript:
Javascript:
var slide = document.getElementById('slide'),
sliderDiv = document.getElementById("sliderAmount");
slide.onchange = function() {
sliderDiv.innerHTML = this.value;
$.ajax({
url: '{{ url_for('main.control_panel', video_id=video.id) }}',
data: $('form').serialize(),
type: 'POST',
success: function(response){
console.log(response);
},
error: function(error){
console.log(error);
}
});
}
Python:
@main.route("/control_panel/<int:video_id>", methods=['GET', 'POST'])
def control_panel(video_id):
video = video.query.get_or_404(video_id)
if request.method == 'POST':
... #IF ELIF for various button functions here
volume = request.form['slider']
return json.dumps({'volume': volume})
return render_template('/control_panel.html', title=video.video, video=video)
在我努力与我上面提到的js/ajax知识一起在网络上寻找解决方案的过程中,任何支持将不胜感激.
Any support would be greatly appreciated as I'm struggling to find solutions on the web along with me aforementioned js/ajax knowledge.
谢谢
这是问题的重演:
python:
from flask import Flask, request, redirect, url_for, render_template, json
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def control_panel():
if request.method == 'POST':
if request.form['button'] == 'button-play':
print("play button pressed")
elif request.form['button'] == 'button-exit':
print("exit button pressed")
elif request.form['slider']:
volume = request.form['slider']
return json.dumps({'volume': volume})
print(volume)
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
HTML:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<title>Slider</title>
</head>
<body>
<div class="container" id="control_panel_1">
<form action="/" method ="post" enctype="multipart/form-data" id="form">
<div class="row">
<div class="col">
<button class="btn btn-primary" button type="submit" name="button" value="button-play">PLAY</button>
<button class="btn btn-primary" button type="submit" name="button" value="button-exit">EXIT</button>
<input id="slide" type="range" min="1" max="100" step="1" value="10" name="slide">
<div id="sliderAmount"></div>
</div>
</div>
</form>
<!--- SCRIPTS --->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
</body>
<script>
var slide = document.getElementById('slide'),
sliderDiv = document.getElementById("sliderAmount");
slide.onchange = function() {
sliderDiv.innerHTML = this.value;
$.ajax({
url: '/index.html',
data: $('form').serialize(),
type: 'POST',
success: function(response){
console.log(response);
},
error: function(error){
console.log(error);
}
});
}
</script>
</html>
推荐答案
问题是因为 $('form').serialize()
仅发送来自< input> 的值code>但不是来自
< button>
,而是在Flask中检查 request.form ['button']
,由于键 button
,它会引发错误字典 request.form
中不存在.
Problem is because $('form').serialize()
sends only values from <input>
but not from <button>
but in Flask you check request.form['button']
and it raises error because key button
doesn't exists in dictionary request.form
.
您必须使用
request.form.get('button')
,然后当字典中不存在 button
时,它返回 None
.
and then it returns None
when button
doesn't exists in dictionary
顺便说一句:
-
您只有
@ app.route("/",...)
,因此AJAX必须发送到/
,而不是/index.html
you have only
@app.route("/", ...)
so AJAX has to send to/
, not to/index.html
在 return ...之后使用
是没有用的,因为 print(volume)
return
终止了功能
在Flask中,您可以使用 return jsonify(dict)
代替 return json.dumps(dict)
,然后发送特殊的标头,然后JavaScript将其转换为对象,您可以获取 response.volume
.使用 json.dumps(dict)
将其作为html/text发送,您将不得不使用 JSON.parse(response).volume
in Flask you can use return jsonify(dict)
instead of return json.dumps(dict)
and then it sends special headers and JavaScript converts it to object and you can get response.volume
. Using json.dumps(dict)
it sends it as html/text and you would have to use JSON.parse(response).volume
在一个文件中工作代码(使用 template_render_string
而不是 template_render
),这样每个人都可以轻松地对其进行测试.
Working code in one file (using template_render_string
instead of template_render
) so everyone can easily test it.
from flask import Flask, request, redirect, url_for, render_template, json, render_template_string, jsonify
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def control_panel():
print('request.form:', request.form)
if request.method == 'POST':
if request.form.get('button') == 'button-play':
print("play button pressed")
elif request.form.get('button') == 'button-exit':
print("exit button pressed")
elif request.form.get('slide'):
volume = request.form.get('slide')
print('volume:', volume)
#return jsonify({'volume': volume})
return json.dumps({'volume': volume})
print('render')
return render_template_string('''<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<title>Slider</title>
</head>
<body>
<div class="container" id="control_panel_1">
<form action="/" method ="post" enctype="multipart/form-data" id="form">
<div class="row">
<div class="col">
<button class="btn btn-primary" button type="submit" name="button" value="button-play">PLAY</button>
<button class="btn btn-primary" button type="submit" name="button" value="button-exit">EXIT</button>
<input id="slide" type="range" min="1" max="100" step="1" value="10" name="slide">
<div id="sliderAmount"></div>
</div>
</div>
</form>
<!--- SCRIPTS --->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
</body>
<script>
var slide = document.getElementById('slide'),
sliderDiv = document.getElementById("sliderAmount");
slide.onchange = function() {
sliderDiv.innerHTML = this.value;
$.post({
url: '/',
data: $('form').serialize(),
success: function(response){
alert(response);
alert(response.volume); // works with jsonify()
alert(JSON.parse(response).volume); // works with json.dumps()
console.log(response);
},
error: function(error){
alert(response);
console.log(error);
}
});
}
</script>
</html>''')
if __name__ == '__main__':
app.run(debug=True, use_reloader=False)
这篇关于HTML范围滑块可通过AJAX调用到Flask的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!