Flask app is running correct function, but not rendering template

Question:

I have a flask app with a template. I am attempting to send via post several items collected by javascript when the user clicks a button. When I post my data to /confirm, the print statement executes, but the render_template function does not render anything, my web browser stays on the /likes page.

Here is the 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("Print the data: {}".format(foo))
    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)

And here is the template:

{% 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 loop logic of jinja template -->
            {%for user_data in liking_user_list%}
            <!-- Table rows -->
            <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 () {
        // Add click event listener to a button with an ID of "danger-report"
        $('#danger-report').click(function () {
            // Get all the buttons with the btn-danger class
            var dangerButtons = $('.btn-danger');

            // Filter out the rows that contain the danger buttons
            var dangerRows = dangerButtons.parents('tr');

            // Define an empty list to store the contents of the <td> elements
            var tdContents = [];

            // Log the number of danger rows and their contents to the console
            dangerRows.each(function () {
                var name = $(this).find('td:eq(0)').text(); // Get the text content of the first <td> element in the row
                var id = $(this).find('td:eq(1)').text(); // Change '1' to the index of the <td> you want to log
                var url = $(this).find('td:eq(2)').text(); // Change '1' to the index of the <td> you want to log
                var followers = $(this).find('td:eq(3)').text(); // Change '1' to the index of the <td> you want to log
                var verified = $(this).find('td:eq(4)').text(); // Change '1' to the index of the <td> you want to log


                var item = { "name": name, "id": id, "url": url, "followers": followers, "verified": verified }

                tdContents.push(JSON.stringify(item));
            });

            //console.log(tdContents)
            // Join the contents of the tdContents array with commas
            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;
                //alert("Success: " + r.responseText);
                console.log("Sent");
            };
            // Send data in below way from JS
            r.send(JSON.stringify({ "data": dataToSend }));
        });
    });
</script>
{% endblock %}

I can’t figure out why when posting r.send the template isn’t rendered. Any ideas?

UPDATE:
Here is the updated routing:

@app.route('/confirm', methods=['POST','GET'])
def confirm():
    if request.method == 'POST':
        #block_list = json.loads(request.data.decode())["data"]
        # print("Print the data: {}".format(foo))
        block_list = json.loads(request.data.decode())['data']
        #print(block_list)
        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)

And here is the function where the POST request is sent. Is this where I need to do the redirecting?

    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;
        //alert("Success: " + r.responseText);
        console.log("Sent");
        //window.location.href = "/confirm"; // Redirect to /confirm
    };
    // Send data in below way from JS
    r.send(JSON.stringify({ "data": dataToSend }));
    
    window.location.href = "/confirm";
Asked By: mowsie2k

||

Answers:

You can simplify the logic by sending the ids of the selected rows to the /confirm endpoint. Then let the endpoint figure our what data the ids represent and render it for you.

@app.route('/confirm', methods=['GET'])
def confirm():
  args = request.args
  ids = args.get('ids')
  id_list = ids.split(',')
  return render_template('confirm.html', id_list=id_list)
Answered By: Emiel Zuurbier
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.