SnarkShark SnarkShark - 3 months ago 12
HTML Question

Problems redirecting to dynamic URLs in Flask with 'action'

My app has a text box and a submission button. I am trying to create and redirect to dynamic URLs in my app, that are based off of what is typed in the text box. For example, the user enters in '1234', clicks submit, then is taken to 'website.com/results/1234'. The problem seems to be that the HTML for my button doesn't want to redirect the user to the new, dynamic URL. I am passing this to the HTML with Jinja.

Here is what I have.

The user starts on the home page, that is defined like this

@app.route("/home/", methods=["GET", "POST"])
def start():
return render_template("dashboard.html")


Dashboard.html has a text box and submission button (below). As you can see, the
action
of this button is to redirect to
{{ results_page }}
, where "results_page" comes from my Python function
load_results
(also below) and is passed to the HTML with
render_template
.

<div>
<form action="{{ results_page }}" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" placeholder="18952863, 18269575" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>
</div>


The results page of my app uses the user input to look up some information and display it.

@app.route('/results/<query>', methods=["GET", "POST"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'POST':
query = form.pmid.data #This is the user input

results_page = "website.com/results/"+query
return(query)

#do lots of stuff using the query

return render_template('results.html', form=form, results_page = results_page)


except Exception as e:
return(str(e))


If I run my app like this, the home page is fine, but when I click "Submit", the app doesn't take in the user input or do anything with it. Simply the
home
page refreshes.

I am new to web development, but since this code works fine if I hardcode the button to
action = "website.com/results"
in the HTML, AND do without the
<query>
in
/results/<query>
for the results page, I think that only a few adjustments should be needed to make my app dynamically redirect to and load pages correctly. Right now, I'm not sure what I'm missing. Please let me know where I'm going stray.

EDIT -

Now I have implemented a
handle_form
function that redirects to my dynamic URL. This function properly redirects but then I get a 404 error.

@app.route('/form/', methods=["POST"]) #handles form submission
def handle_form():
form = pmidForm(secret_key='super secret key')
if request.method == "POST":
query = request.form['pmid']
return redirect('/results/'+query)


I have also edited my form in the HTML
action
to go to
/form/


<form action="website.com/form/" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" placeholder="18952863, 18269575" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>


With this, my site will properly redirect to
/results/<query>
/ (e.g. /results/1234) but I get a 404 error. Here is how I have changed my
load_results


@app.route('/results/<query>', methods=["GET"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'GET':
query = form.pmid.data #THIS IS THE USER INPUT FROM THE FORM #referencing 'class pmidForm'
return query

.
.
#do stuff


I think I am very close but need to figure out why I am getting a 404 error. My guess is that I am using "GET" incorrectly. My form in the HTML uses
method="post"
. Since this does not match with "GET", is there no way for my
load_results(query)
function to retrieve the contents of the form?

EDIT 2 -

Changed
handle_form
to redirect with
url_for
:

@app.route('/form/', methods=["POST"]) #handles form submission
def handle_form():
form = pmidForm(secret_key='super secret key')
if request.method == "POST":
query = request.form['pmid']
return redirect(url_for('.load_results', query=query))


And changed
load_results
to not return "query"

@app.route('/results/<query>', methods=["GET"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'GET':
query = form.pmid.data # This shouldn't work??
.
.
# do stuff with the variable "query"


With this, it's still returning the 404 Error as before. Should I not be using
if request.method == GET
?

Edit 3 -

Even a very simplified
load_results
will give me the 404 error, so I'm not sure what's up.

@app.route('/results/<query>', methods=["GET", "POST"])
def load_results(query):
q = query
return render_template('test.html', q=q)


EDIT - 3

It seems that the accepted solution IS the correct solution to this problem, however there is an issue with uwsgi in my server that is re-directing it to the wrong location :(

Answer

Your punctual problem is that /home route function also needs to put the results_page url on the templating context.

results_page = "website.com/results"
return render_template("dashboard.html", results_page=results_page)

Since the variable is undefined, flask is calling the original endpoint on the form submission.

Your larger problem is that your appraoch isn't going to get you a dynamic results url that looks like /results/1234.

Typical approaches are to redirect on the server side when you handle the post request; or to use JavaScript in the client to get the form data and change the browser location to /results/1234.

A simplified version of how to handle this with a server side redirect might look something like this. One route that handles the form submission and another that displays results. You simply redirect from one to the other to get the nice url.

@app.route('/form', methods=["POST"])
def handle_form():
   query = form.pmid.data #This is the user input 
   return redirect(url_for('.load_results', query=query))

@app.route('/results/<query>') *removed the method spec to handle the redirect?
def load_results(query):
    .
    .
    # do something with query