如何将JavaScript数组传递至Python Flask后端?
问题:Flask项目中JS数组数据传递到Python端失败
我不是JavaScript专家,正在做一个用Python Flask搭建网站的学校项目。现在遇到的问题是:HTML输入的值已经存入JavaScript数组(genre_list和keyword_list),但无法将这些数组数据传递到Python端处理。尝试使用XMLHttpRequest但效果不佳,以下是初始及修改后的相关代码:
初始代码
HTML
<html> <head> <title>4 Years</title> <meta name='viewport' content='width=device-width, initial-scale=1'> <script src="https://kit.fontawesome.com/7006f68f03.js" crossorigin="anonymous"></script> <link rel="stylesheet" href="static/category.css"> </head> <body> <img src="static/test.jpeg" height="70"> <hr> <form class="content" action="/category/list" method="post" id="myform"> <div class="genres-input"> Genres: <div class="genres-box"> <ul id="genreul"> <input class="input-text" type="text" name="genres" list="genre"> </ul> <datalist id="genre"> <option value="Action"></option> <option value="Adventure"></option> <option value="Animation"></option> <option value="Biography"></option> <option value="Comedy"></option> <option value="Crime"></option> <option value="Documentary"></option> <option value="Drama"></option> <option value="Family"></option> <option value="Fantasy"></option> <option value="Film-Noir"></option> <option value="Game-Show"></option> <option value="History"></option> <option value="Horror"></option> <option value="Music"></option> <option value="Musical"></option> <option value="Mystery"></option> <option value="News"></option> <option value="Reality-TV"></option> <option value="Romance"></option> <option value="Sci-Fi"></option> <option value="Short"></option> <option value="Sport"></option> <option value="Talk-Show"></option> <option value="Thriller"></option> <option value="War"></option> <option value="Western"></option> </datalist> </div> </div> <div class="age-input"> Ages: <div class="ages-box"> <input class="input-text" type="number" name="ages" placeholder=" 0 - 99" min="0" max="99"> </div> </div> <div class="keywords-input"> Keywords: <div class="keywords-box"> <ul id="keyul"> <input class="input-text" type="text" name="keywords"> </ul> </div> </div> <div class="type-input"> Types: <div class="types-box"> <input class="input-text" type="text" name="types" list="type"> <datalist id="type"> <option value="Movie"></option> <option value="TV Series"></option> <option value="Short"></option> <option value="TV Episode"></option> <option value="TV Mini Series"></option> <option value="TV Movie"></option> <option value="TV Special"></option> <option value="TV Short"></option> <option value="Video Game"></option> <option value="Video"></option> <option value="Music Video"></option> <option value="Podcast Series"></option> <option value="Podcast Episode"></option> </div> </div> <div class="search"> <input class="submit" onclick="search_value()" type="button" name="search" value="Search"> </div> </form> <script src="static/category.js"></script> <script src="static/disable_enter.js"></script> </body> </html>
JS
var ul1 = document.querySelector("ul#genreul"), input1 = ul1.querySelector("input"); let genre_list = []; var ul2 = document.querySelector("ul#keyul"), input2 = ul2.querySelector("input"); let keyword_list = []; function createTag1(){ ul1.querySelectorAll("li#genres").forEach(li => li.remove()); console.log(keyword_list.slice().reverse()); genre_list.slice().reverse().forEach(genre =>{ let liTag1 = `<li id='genres'>${genre} <i class="fa-solid fa-x" onclick="remove1(this,'${genre}')"></i></li>`; ul1.insertAdjacentHTML("afterbegin", liTag1); }); } function createTag2(){ ul2.querySelectorAll("li#keywords").forEach(li => li.remove()); console.log(keyword_list.slice().reverse()); keyword_list.slice().reverse().forEach(keyword =>{ let liTag2 = `<li id='keywords'>${keyword} <i class="fa-solid fa-x" onclick="remove2(this,'${keyword}')"></i></li>`; ul2.insertAdjacentHTML("afterbegin", liTag2); }); } function remove1(element, genre){ let index1 = genre_list.indexOf(genre); genre_list = [...genre_list.slice(0, index1), ...genre_list.slice(index1 + 1)]; element.parentElement.remove(); } function remove2(element, keyword){ let index2 = keyword_list.indexOf(keyword); keyword_list = [...keyword_list.slice(0, index2), ...keyword_list.slice(index2 + 1)]; element.parentElement.remove(); } function addTag1(e){ if(e.key == "Enter"){ let genre = e.target.value.replace(/\s+/g, ' ').replace(',',''); if(genre.length > 1 && !genre_list.includes(genre)){ genre_list.push(genre); createTag1(); } e.target.value = ""; } } function addTag2(e){ if(e.key == "Enter"){ let keyword = e.target.value.replace(/\s+/g, ' ').replace(',',''); if(keyword.length > 1 && !keyword_list.includes(keyword)){ keyword_list.push(keyword); createTag2(); } e.target.value = ""; } } function search_value() { console.log(genre_list); console.log(keyword_list); document.getElementById("myform").submit(); } input1.addEventListener("keyup", addTag1); input2.addEventListener("keyup", addTag2);
Python
from flask import Blueprint,request,render_template Category = Blueprint('category',__name__,static_folder='static',template_folder='templates') @Category.route('/category') def category_html():return render_template('category.html') @Category.route('/category/list',methods=['POST','GET']) def category_value(): #genre = ages = request.form["ages"] #keyword = types = request.form['types'] print(ages,types) return render_template('list.html',text2=ages,text4=types)
修改后的代码
JS
var ul1 = document.querySelector("ul#genreul"), input1 = ul1.querySelector("input"); let genre_list = []; var ul2 = document.querySelector("ul#keyul"), input2 = ul2.querySelector("input"); let keyword_list = []; function createTag1(){ ul1.querySelectorAll("li#genres").forEach(li => li.remove()); console.log(keyword_list.slice().reverse()); genre_list.slice().reverse().forEach(genre =>{ let liTag1 = `<li id='genres'>${genre} <i class="fa-solid fa-x" onclick="remove1(this,'${genre}')"></i></li>`; ul1.insertAdjacentHTML("afterbegin", liTag1); }); } function createTag2(){ ul2.querySelectorAll("li#keywords").forEach(li => li.remove()); console.log(keyword_list.slice().reverse()); keyword_list.slice().reverse().forEach(keyword =>{ let liTag2 = `<li id='keywords'>${keyword} <i class="fa-solid fa-x" onclick="remove2(this,'${keyword}')"></i></li>`; ul2.insertAdjacentHTML("afterbegin", liTag2); }); } function remove1(element, genre){ let index1 = genre_list.indexOf(genre); genre_list = [...genre_list.slice(0, index1), ...genre_list.slice(index1 + 1)]; element.parentElement.remove(); } function remove2(element, keyword){ let index2 = keyword_list.indexOf(keyword); keyword_list = [...keyword_list.slice(0, index2), ...keyword_list.slice(index2 + 1)]; element.parentElement.remove(); } function addTag1(e){ if(e.key == "Enter"){ let genre = e.target.value.replace(/\s+/g, ' ').replace(',',''); if(genre.length > 1 && !genre_list.includes(genre)){ genre_list.push(genre); createTag1(); } e.target.value = ""; } } function addTag2(e){ if(e.key == "Enter"){ let keyword = e.target.value.replace(/\s+/g, ' ').replace(',',''); if(keyword.length > 1 && !keyword_list.includes(keyword)){ keyword_list.push(keyword); createTag2(); } e.target.value = ""; } } function search_value() { console.log(genre_list); console.log(keyword_list); var xhr = new XMLHttpRequest(); var url = 'http://127.0.0.1:5000/category'; xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'application/json'); var jsonData = JSON.stringify({ data: genre_list }); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { console.log(xhr.responseText); } }; xhr.send(jsonData); } document.getElementById("myform").addEventListener("submit", search_value); input1.addEventListener("keyup", addTag1); input2.addEventListener("keyup", addTag2);
Python
from flask import Blueprint,request,render_template Category = Blueprint('category',__name__,static_folder='static',template_folder='templates') @Category.route('/category') def category_html():return render_template('category.html') @Category.route('/category/list',methods=['POST','GET']) def category_value(): genre = request.get_json(force=True) print(genre) ages = request.form["ages"] #keyword = types = request.form['types'] print(ages,types) return render_template('list.html',text2=ages,text4=types)
问题原因与解决办法
核心问题
- 请求地址不匹配:修改后的JS中XHR请求的是
/category,但Python处理数据的路由是/category/list,且该路由同时尝试处理表单数据和JSON数据,两种格式无法共存(request.form和request.get_json不能同时获取有效数据)。 - 表单提交与XHR冲突:原有代码既触发表单默认提交,又发送XHR请求,逻辑混乱导致数据传递失败。
方案一:隐藏表单字段传递数组(低改动)
无需使用XHR,在表单中添加隐藏字段,提交前将数组转为逗号分隔的字符串存入字段:
- HTML新增隐藏字段:在
<form>内添加
<input type="hidden" name="genre_list" id="genre_list"> <input type="hidden" name="keyword_list" id="keyword_list">
- 修改JS的
search_value函数:
function search_value() { console.log(genre_list); console.log(keyword_list); // 将数组转为逗号分隔字符串存入隐藏字段 document.getElementById("genre_list").value = genre_list.join(","); document.getElementById("keyword_list").value = keyword_list.join(","); document.getElementById("myform").submit(); }
- 修改Python代码:
@Category.route('/category/list',methods=['POST','GET']) def category_value(): # 将字符串转回数组,处理空值情况 genre_list = request.form.get("genre_list", "").split(",") genre_list = genre_list if genre_list != [""] else [] keyword_list = request.form.get("keyword_list", "").split(",") keyword_list = keyword_list if keyword_list != [""] else [] ages = request.form.get("ages", "") types = request.form.get("types", "") print(genre_list, keyword_list, ages, types) return render_template('list.html',text2=ages,text4=types, genres=genre_list, keywords=keyword_list)
方案二:纯AJAX请求(无页面跳转)
如果不需要页面跳转,用XHR发送所有数据(包括ages、types):
- 修改JS的
search_value函数:
function search_value(e) { // 阻止表单默认提交行为 e.preventDefault(); console.log(genre_list); console.log(keyword_list); // 收集所有表单数据 const ages = document.querySelector("input[name='ages']").value; const types = document.querySelector("input[name='types']").value; var xhr = new XMLHttpRequest(); var url = '/category/list'; // 使用相对路径避免跨域问题 xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'application/json'); var jsonData = JSON.stringify({ genres: genre_list, keywords: keyword_list, ages: ages, types: types }); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { console.log(xhr.responseText); // 可根据需求处理返回结果,比如跳转页面: // window.location.href = '/category/list'; } }; xhr.send(jsonData); } // 监听表单提交事件 document.getElementById("myform").addEventListener("submit", search_value);
- 修改Python代码:
@Category.route('/category/list',methods=['POST','GET']) def category_value(): if request.method == 'POST': data = request.get_json() genre_list = data.get("genres", []) keyword_list = data.get("keywords", []) ages = data.get("ages", "") types = data.get("types", "") print(genre_list, keyword_list, ages, types) return render_template('list.html',text2=ages,text4=types, genres=genre_list, keywords=keyword_list) else: return render_template('list.html')
额外注意事项
- 使用相对路径而非绝对路径,避免部署时的跨域或端口变化问题。
- 使用AJAX时必须阻止表单默认提交行为,否则页面跳转会中断AJAX请求。
- 处理空值情况,避免空数组转为
[""]这类无效数据。
内容的提问来源于stack exchange,提问作者ilovemath
相关产品推荐
相关产品推荐

