-
Notifications
You must be signed in to change notification settings - Fork 4
hidden values
It is common to need to break a form up into multiple pieces from time-to-time. This is often done when the second page of the form depends on information submitted on the first page. This is less common than it used to be (because we have JavaScript now), but imagine the way Bannerweb used to work, which is the following: The first form asks you to pick a semester, then you hit submit, then the next page asks for the department to list classes for, then you hit submit again, then you get a list of classes for that semester and department combination.
Here is the exchange of information between browser (the client) and the server:
Client Server
===================================================================
Client requests schedule of classes ----------------------->
<----------- Server sends back list of possible semesters,
including blank HTML form.
Client fills out form (drop down of
semester) and sends to server ---------------------------->
<---------- Server reads semester variable from form,
sends list of departments for that semester.
Client picks from list of departments,
but when they submit the form, how do
they send the semester again? The server
has forgotten it! ----------------------------------------->
Server needs to know both semester and
department here.
One solution to this problem is to have the server, in its first response to the client, send not only the list of departments back to the client, but also the semester that the client chose. Remember, both the client and server are very forgetful, so the client has already forgotten what semester was picked in the previous step. The server can remind them explicitly, however. This is done by having the server, when it generates the HTML form for the list of departments, also include a hidden field in the HTML form that includes the name of the semester. Hidden fields are invisible to the user of the website but they are submitted just like regular fields.
Try this code, which uses hidden fields to allow the user to resubmit the random number generator as many times in a row as they want, using the same values. Note that you don't need any changes to your Python code, only the HTML code.
Change random2.html to:
<html>
<head>
<title>Random numbers</title>
</head>
<body>
<h1>Random number generator</h1>
{% if number is not defined %}
<form action="{{ url_for('random_number2') }}" method="post">
Enter an lower limit: <input type="text" name="lowerlim"><br>
Enter an lower limit: <input type="text" name="upperlim"><br>
<input type="submit" value="Generate number">
</form>
{% else %}
Your random number is {{ number }}.
As a reminder, your desired range was between {{ low }} and {{ high }}.<br>
<form action="{{ url_for('random_number2') }}" method="post">
<input type="submit" value="Generate another number with same range.">
<input type="hidden" name="lowerlim" value="{{ low }}">
<input type="hidden" name="upperlim" value="{{ high }}">
</form>
{% endif %}
</body>
</html>And change the Python route to:
@app.route("/random_number2", methods=['get', 'post'])
def random_number2():
if "upperlim" not in request.form:
return render_template("random2.html")
else:
lower = int(request.form['lowerlim'])
upper = int(request.form['upperlim'])
n = random.randint(lower, upper)
return render_template("random2.html", number=n, low=lower, high=upper)Run the webpage that uses the code above, and generate a bunch of random numbers. Make sure you understand this code before continuing below. IF IT DOESN'T MAKE SENSE, ASK ME FOR CLARIFICATION.
Modify the code above so whenever a random number is generated, it also tells you how many times you have generated a number with those upper/lower limits in a row. In other words, when the user first comes to the webpage, they should be able to enter their upper/lower limits. Then they hit submit, it shows a random number, and also a message that says "You've generated 1 number(s)." Then they hit submit again and it shows another random number, but the message has changed to "You've generated 1 number(s)." And so on.
How to do it:
- We will use a variable called
timesin our HTML template to store the number of times a number has been generated. - Edit your HTML template first. Add a hidden field to the part of the template that runs before the user has picked their limits:
<input type="hidden" name="times" value="0">- This way, when the form is submitted for the first time, a variable called
timesis created whose value is zero. - In the second part of the template (the part that runs after limits have been picked), add this to the form:
<input type="hidden" name="times" value="{{ times }}">- What this does is make it so the HTML template (1) expects Flask to send it a variable called
times, and (2) the HTML template will pass the sametimesvariable right back whenever the form is submitted. -
What you need to do is edit the Python program to make the following changes:
- Make the second part of the program capture the
timesvariable from the form. - Increment the variable and send it back to the HTML template through a keyword argument in
render_template.
- Make the second part of the program capture the
Try it out! If you get stuck, ask me for help. If after trying a lot, you still can't get it, look below. .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
random2.html:
<html>
<head>
<title>Random numbers</title>
</head>
<body>
<h1>Random number generator</h1>
{% if number is not defined %}
<form action="{{ url_for('random_number2') }}" method="post">
Enter an lower limit: <input type="text" name="lowerlim"><br>
Enter an lower limit: <input type="text" name="upperlim"><br>
<input type="hidden" name="times" value="0">
<input type="submit" value="Generate number">
</form>
{% else %}
Your random number is {{ number }}.<br>
As a reminder, your desired range was between {{ low }} and {{ high }}.<br>
You have generated {{ times }} random number(s).<br>
<form action="{{ url_for('random_number2') }}" method="post">
<input type="submit" value="Generate another number with same range.">
<input type="hidden" name="lowerlim" value="{{ low }}">
<input type="hidden" name="upperlim" value="{{ high }}">
<input type="hidden" name="times" value="{{ times }}">
</form>
{% endif %}
</body>
</html>@app.route("/random_number2", methods=['get', 'post'])
def random_number2():
if "upperlim" not in request.form:
return render_template("random2.html")
else:
lower = int(request.form['lowerlim'])
upper = int(request.form['upperlim'])
times = int(request.form['times'])
n = random.randint(lower, upper)
return render_template("random2.html", number=n, low=lower, high=upper, times=times+1)Note that this is not the only way you could have done this. You could also have put times=0 as a keyword argument
in the first call to render_template instead of using a 0 explicitly in the HTML template. You also could have not used a hidden field for times the first time the form is submitted, but in that case you would have had three sections in your Python code:
- one to check for the situation where the form hasn't been submitted at all, and generate the form with fields for upper and lower limit, (check would be
"upperlim" not in request.form) - one to check for the situation where the form has been submitted once, (because the first submission won't have a times field), (check would be
"upperlim" in request.form and "times" not in request.form) and - one to check for the situation where the form has been submitted at least twice, where both variables upperlim and times will exist.
Try the following:
- Make another route that lets the user type in a pair of (x, y) coordinates (on a webpage) and have Python/flask calculate the distance between the two points and print it out (again, on a webpage). This will require a new webpage (html file) where the user can enter the coordinates, as well as a new Flask route to do the calculations.
Use the main wiki page to navigate, not the list of pages directly above, because those are out of order.