Flask函数执行正常但模板无法渲染问题排查求助
问题
开发了一个带模板的Flask应用,需求是用户点击按钮时,通过JavaScript收集多项数据并以POST方式提交至/confirm路由。目前POST请求已触发,路由函数内的print语句可正常执行,但render_template函数未能渲染confirm.html模板,浏览器始终停留在/likes页面。相关代码如下:
web_interface.py 原代码
#!/bin/python3 from flask import Flask, render_template, request, url_for, redirect import twitter as twitter from dataclasses import dataclass import json app = Flask(__name__) form_data = {} tweet_data = {} @app.route("/") def index(): return render_template("index.html") @app.route("/likes", methods=['POST','GET']) def likes(): if request.method == 'POST': tweet_url = request.form['inputTweetURL1'] liking_user_list = twitter.liking_users_lookup_by_url(tweet_url) return render_template("likes.html", liking_user_list=liking_user_list) else: return render_template("likes.html") @app.route('/confirm', methods=['POST']) def confirm(): block_list = json.loads(request.data.decode())['data'] print(block_list) return render_template("confirm.html", block_list=block_list) app.run(host="0.0.0.0", port=80)
模板代码
{% extends 'base.html' %} {% block content %} <form method='POST'> <div class="mb-3"> <label for="inputTweetURL1" class="form-label">Tweet URL</label> <input type="text" class="form-control" name="inputTweetURL1" id="inputTweetURL1" aria-describedby="inputTweetURL1Help"> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> <div class="scrollme"> <table class="table table-striped"> <!-- Table headers --> <thead> <tr> <th scope="col">#</th> <th scope="col">Name</th> <th scope="col">User ID</th> <th scope="col">Profile URL</th> <th scope="col">Follower Count</th> <th scope="col">Verified Status</th> <th scope="col">Block User</th> </tr> </thead> <!-- Table body --> <tbody class="table-group-divider"> {%for user_data in liking_user_list%} <tr> <th scope="row">1</th> <td>{{user_data['name']}}</td> <td>{{user_data['id']}}</td> <td><a href="https://twitter.com/{{ user_data.username }}">https://twitter.com/{{ user_data['username'] }}</a></td> <td>{{user_data['public_metrics']['followers_count']}}</td> <td>{{user_data['verified']}}</td> <td><a><button type="button" class="btn btn-primary toggle-button">Block</button></a></td> {%endfor%} </tr> </tbody> </table> <button type="submit" id="danger-report" class="btn btn-primary">Submit</button> <input type="hidden" name="hiddenInput" id="hiddenInput"> </div> <script> $(document).ready(function () { $('#danger-report').click(function () { var dangerButtons = $('.btn-danger'); var dangerRows = dangerButtons.parents('tr'); var tdContents = []; dangerRows.each(function () { var name = $(this).find('td:eq(0)').text(); var id = $(this).find('td:eq(1)').text(); var url = $(this).find('td:eq(2)').text(); var followers = $(this).find('td:eq(3)').text(); var verified = $(this).find('td:eq(4)').text(); var item = { "name": name, "id": id, "url": url, "followers": followers, "verified": verified } tdContents.push(JSON.stringify(item)); }); var dataToSend = tdContents.join(','); var r = new XMLHttpRequest(); r.open("POST", "http://127.0.0.1/confirm", true); r.onreadystatechange = function () { if (r.readyState != 4 || r.status != 200) return; console.log("Sent"); }; r.send(JSON.stringify({ "data": dataToSend })); }); }); </script> {% endblock %}
更新后的路由代码
@app.route('/confirm', methods=['POST','GET']) def confirm(): if request.method == 'POST': block_list = json.loads(request.data.decode())['data'] print('youre posting, it worked') return render_template("confirm.html", block_list=block_list) else: block_list = json.loads(request.data.decode())['data'] print('youre gettin') return render_template('confirm.html', block_list=block_list)
更新后的JavaScript请求代码
var r = new XMLHttpRequest(); r.open("POST", "http://127.0.0.1/confirm", true); r.onreadystatechange = function () { if (r.readyState != 4 || r.status != 200) return; console.log("Sent"); }; r.send(JSON.stringify({ "data": dataToSend })); window.location.href = "/confirm";
排查思路
核心逻辑错误:AJAX请求的特性
你用XMLHttpRequest(AJAX)发送POST请求,这类请求是后台异步请求,浏览器不会自动跳转到响应页面。Flask返回的render_template内容只会作为AJAX的响应体返回,不会主动替换当前页面或触发跳转。更新后代码的矛盾点
你在发送AJAX请求后立刻执行window.location.href = "/confirm",这会触发一个GET请求到/confirm路由,但你的GET分支尝试读取request.data(仅POST请求有请求体),会直接抛出JSON解析错误,导致无法渲染模板。可行解决方案
改用传统表单提交
将收集到的数据存入隐藏表单字段,点击按钮时提交表单,让浏览器自动处理响应:$('#danger-report').click(function (e) { e.preventDefault(); var tdContents = []; // 保留原数据收集逻辑 dangerRows.each(function () { // ... 原数据收集代码 ... }); $('#hiddenInput').val(JSON.stringify(tdContents)); $(this).closest('form').submit(); });同时修改Flask路由读取表单数据:
@app.route('/confirm', methods=['POST']) def confirm(): block_list = json.loads(request.form['hiddenInput']) return render_template("confirm.html", block_list=block_list)保留AJAX,手动处理响应
在AJAX请求成功后,用返回的HTML替换当前页面,或跳转到带参数的GET路由:var r = new XMLHttpRequest(); r.open("POST", "/confirm", true); r.setRequestHeader("Content-Type", "application/json"); r.onreadystatechange = function () { if (r.readyState === 4 && r.status === 200) { // 方式1:替换当前页面内容 document.body.innerHTML = r.responseText; // 方式2:跳转到GET路由(需修改路由从request.args读取数据) // window.location.href = "/confirm?data=" + encodeURIComponent(dataToSend); } }; r.send(JSON.stringify({ "data": dataToSend }));
额外错误修复
- GET分支中
json.loads(request.data.decode())会报错:GET请求无请求体,request.data为空,直接解析会触发JSONDecodeError。 - AJAX请求未设置
Content-Type请求头,Flask可能无法正确解析JSON数据,需添加r.setRequestHeader("Content-Type", "application/json");。 - 模板中
#danger-report按钮在<form>标签外,默认点击不会触发表单提交,需注意作用域。
- GET分支中
内容的提问来源于stack exchange,提问作者mowsie2k
相关产品推荐
相关产品推荐

