0

I'm trying to create a basic web app that has an HTML form on the root landing page, and then after submission, run a postgresql query with the desired input and redirect the user to a page with a generated matplotlib chart of their input. In my main function, I have the following:

@app.route('/', methods=['POST'])
def main():
    return render_template("main.html")

So let's say I have my main html file being rendered by the flask app. I have another route below:

@app.route('/query', methods=['POST'])
def queryPage():
    # code to execute query with information 
    # passed from the main.html template
    # then generate chart via matplotlib via returned information
    return render_template("query.html")

I'm confused as to how to get my input from the form in main.html to send information back to the application for rendering at the /query endpoint. If someone could elaborate on this, I'd appreciate it. Front end is not my strong suit. Thanks!

danielschnoll
  • 3,045
  • 5
  • 23
  • 34

2 Answers2

1

You need a form on main.html... maybe like this (note the form action):

<form action = /query method="POST">
        <label for="username">USERNAME:</label>
        <input type="text" name="username" id="username" size="15">
        <input type="submit" name="submit" id="submit"/>
</form>

When that form gets sent (after a user clicks a button lets say), the route in your flask code that matches the action (/query in this case) will get called and execute. Also the name= variables in any of your form elements will be available in your request on the back end (I'm using the variable username as an example). You can get them like this: request.form['username']. Other form variables (like a check box) will be slightly different.

Anyway in your case you need a /query action in your html somewhere in main.html.... It could be called by a button or timed javascript etc...

When this /query action is called on your main.html, you need to

return render_template('query.html, username=username)

and then the username variable will be available on the query.html page.

Keep in mind I only passed a single variable. You can pass a multiple variables, lists, dictionaries etc...

Also keep in mind any variable that you return to query.html can be made extremely dynamic using Jinja templating. You can loop through lists and print different html tags etc and use logic within your html... possible depending on what the values are that get returned to the page.

m.a.d.cat
  • 195
  • 2
  • 8
1

If I understand your question correctly then you are having difficulty passing the form information from your main function to the separate queryPage function for rendering. This can easily be achieved by providing the values you wish to pass as keyword arguments to the url_for function. These can then be retrieved from request.args within the queryPage function. Given the fact that you are returning query.html from this function and not an image, I assume that you are intending on displaying your chart within an img tag in query.html. In this case you will need another view function to generate and return the image itself. You may also need to disable browser caching for this endpoint to prevent browsers treating your dynamic image as if it were a static image https://stackoverflow.com/a/2068407/10548137.

@app.route('/', methods=['GET', 'POST'])
def main():
    form = MyForm(request.form)
    if request.method == "POST" and form.validate():
        return redirect(url_for("queryPage", **form.data))
    return render_template("main.html", form=form)

@app.route('/query', methods=['GET'])
def queryPage():
    arguments = request.args.to_dict()
    image_url = url_for("make_chart", **arguments)
    return render_template("query.html", image_url=image_url)

@app.route('/make_chart', methods=['GET'])
def make_chart():
    arguments = request.args.to_dict()
    # perform postgres query here using arguments
    # generate matplotlib chart here using query results
    # ? save chart in BytesIO buffer in png format        
    response = send_file(file_pointer, mimetype="image/png")
    # just return response here if don't need to alter headers
    response = make_response(response)
    response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "0"
    return response
EAW
  • 628
  • 6
  • 10