i have seen two different ways of handling post requests on a route:
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
# insert logic on data
return render_template('register.html', title="Register", form=form)
and:
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
# insert logic
I cannot seem to find a clear answer to the following questions, and i cant seem to find a duplicate in SO:
- Do they refer to different use cases?
- Should both be used? Are they redundant?
Thanks in advance!
CodePudding user response:
Your first method will execute on either situation: "user requests the data [GET]" or "user posts a form [POST]". Use the second method if want to assign both the GET and POST requests to the same route.
See the code below :
if request.method == "POST":
# HTTP Method POST. That means the form was submitted by a user
# and we can find her filled out answers using the request.POST QueryDict
else:
# Normal GET Request (most likely).
# We should probably display the form, so it can be filled
# out by the user and submitted.
Or you will want to create different route function, one that will post your form and another that will redirect you to get function after you post your data if this is what you are looking for.
@app.route('/register', methods=['POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
# redirect to '/register_success' with user data
@app.route('/register_success',methods=['GET'])
def registration_success():
# render <You are registered 'user'> --etc--
CodePudding user response:
The GET method should not be used to transmit sensitive information (like passwords), as GET encodes form data in the URL, whereas POST data is sent in the request body. W3Schools has a fairly simple comparison between GET and POST methods, further explaining the differences between the two. Just note that POST does not guarantee security, but GET ensures lack thereof.
As for implementation using Flask, you can use distinct URLs (one for getting the registration form, and another to send the data back to the server), but you can also use the same URL, and handle each request differently. The most important thing is to ensure that your client-side code (the HTML) sends the data to the server using POST, not GET.
Following is some code which I hope demonstrates the difference. Browsing to both /register
and /reg_with_method
should work well for the "registration flow". However, submitting the form from /register_with_get
should let you know that the secret key is now in the address bar.
from flask import Flask, request
app = Flask(__name__)
registration_form = '''
<html>
<head><title>Registeration form</title></head>
<body>
{additional_message}
<form action="{location}" method="{method}">
<input type="text" name="username" value="UserName"><br>
<input type="text" name="registration_key" value="Key"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
'''
registration_success = '''
<html>
<head><title>Registeration complete</title></head>
<body>
Successfully registerd user {username}.
</body>
</html>
'''
@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
return post_registration_form(location="/register")
# default to GET, but you can add other methods or error handling
return get_registration_form(location="/register")
@app.route("/register_with_get")
def register_get_only():
if request.args.get("registration_key"): # The key is now in the address bar
return get_registration_form(location="/register", additional_message="SECURITY: The SIKRIT key is now in the address bar. Now we will use POST.<br>")
return get_registration_form(location="/register_with_get", method="get") # This is a BAD IDEA, the key will be in the address bar.
@app.get("/reg_with_method")
def get_registration_form(location = "/reg_with_method", additional_message = "", method = "post"):
return registration_form.format(location=location, additional_message=additional_message, method=method)
@app.post("/reg_with_method")
def post_registration_form(location = "/reg_with_method"):
if request.form.get("registration_key") != "SIKRIT":
return get_registration_form(location=location, additional_message="Bad sikrit key! try again..<br>")
return registration_success.format(username=request.form.get("username"))
if __name__ == "__main__":
app.run()
Note: This is an oversimplified version of things. This is not how a proper Flask app should be written, but I opted to avoid complicating things with templates and response objects to focus on the question at hand.