You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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解析错误,导致无法渲染模板。

  • 可行解决方案

    1. 改用传统表单提交
      将收集到的数据存入隐藏表单字段,点击按钮时提交表单,让浏览器自动处理响应:

      $('#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)
      
    2. 保留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>标签外,默认点击不会触发表单提交,需注意作用域。

内容的提问来源于stack exchange,提问作者mowsie2k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:28:09