Search code examples
flaskhttp-redirect

Returning redirect() and render_template() do nothing (Python Flask)


I am new to Flask so apologies if I am missing something obvious. I've created a basic RAG chatbot that can be asked questions about a specific project kit instruction document. I use a menu that the user will select a specific kit from and when a new kit is selected it will send a new request to the route "/" with new query parameters. The page should re-render with the new query parameters passed as context to render_template(). The parameters are the chroma collection (collection) and the metadata (name) that I use to query the chroma embeddings.

For example, I have a paragraph on the page that is "Please ask me any questions about the {{ name }} kit!" This should update to the name of the current kit after the request but it does not change. I also pass the context variables to a get request that gets a response from the chatbot. Everything else works but the context variables don't change.

I was unable to make this approach work, so I decided to first redirect to the new url with the updated query parameters, and then render the page after it had been redirected. This doesn't work either. The code I attached is from this attempt. I added a new query parameter r that is set to 1 to redirect the page and any other value should just return render_template().

I think this may be a caching problem but I am not sure if it is or if it is how to fix it. I am using the latest version of Chrome on a Mac M1 Max. If there is a simpler or better way to do this please let me know. Thank you for your help!

TLDR: Everything seems to work and the output seems correct but the actual webpage and url do not change at all when I redirect or render the page. I have to manually type in a new url to update the page.

Edit: I replicated this problem in a minimal Flask app following the same approach. I uploaded the app.py, index.html, and Flask output here: https://github.com/pauburk/flask-bug-2024.

app.py:

@app.route("/")
def home():
    r = int(request.args.get("r")) if request.args.get("r") else 0
    collection = request.args.get("collection")
    name = request.args.get("name")

    print("current params:  ", collection, name, r, type(r), file=sys.stderr)
    
    if r == 1:
        url = url_for(".home", collection=collection, name=name) # _external=True, 
        print(f"redirecting to '{url}'...", file=sys.stderr)
        return redirect(url, code=302)
    else:
        print("rendering...", file=sys.stderr)
        return render_template("index.html", collection=collection, name=name, populated_buttons=Markup(populated_buttons_html))

index.html:

function changeTo(collection_value, name_value) {
    $.get("/", { r: 1, collection: collection_value, name: name_value }).done(function () {
        # hide menu modal
    });
}

flask output in terminal: (added names to the printed params for clarity)

$ python3 app.py

 * Serving Flask app 'app'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
current params:  collection="idea_sheets", name="Puppy Programming" r=0 <class 'int'>
rendering...
127.0.0.1 - - [24/Jul/2024 11:50:01] "GET /?r=0&collection=idea_sheets&name=Puppy%20Programming HTTP/1.1" 200 -
127.0.0.1 - - [24/Jul/2024 11:50:01] "GET /static/images/bot-logo.png HTTP/1.1" 304 -
127.0.0.1 - - [24/Jul/2024 11:50:01] "GET /static/styles/app.css HTTP/1.1" 304 -

current params:  collection="idea_sheets" name="Puff Rocket" r=1 <class 'int'>
redirecting to '/?collection=idea_sheets&name=Puff+Rocket'...
127.0.0.1 - - [24/Jul/2024 11:50:03] "GET /?r=1&collection=idea_sheets&name=Puff%20Rocket HTTP/1.1" 302 -

current params:  collection="idea_sheets" name="Puff Rocket" r=0 <class 'int'>
rendering...
127.0.0.1 - - [24/Jul/2024 11:50:03] "GET /?collection=idea_sheets&name=Puff+Rocket HTTP/1.1" 200 -

Solution

  • Looking at your example in https://github.com/pauburk/flask-bug-2024...

    In your index_simple.html template, you're using jQuery to make an AJAX GET request with an updated name. AJAX requests don't automatically reload the page or change the URL. They're designed to update parts of the page without a full reload.

    Redirect after AJAX: When you return a redirect in a response to an AJAX request, the browser doesn't automatically follow that redirect. The redirect response is returned to the JavaScript that made the AJAX call, but it doesn't affect the current page.

    Instead of issuing an AJAX call with:

    $.get("/test_render/", { name: "Bob" });
    

    you can use a simple <a href="..." link or make the browser update the URL like so:

    window.location.href = `/test_render/?name=Bob`;