I'm newbie to flask,I have such a form:
<form class="form" action={{ url_for('/login') }} method="POST">
<input type="text" name="usename" placeholder="Username">
<input type="password" name="password" placeholder="Password">
<button type="submit" id="login-button">Login</button>
</form>
I use request.form()and request.form.get() to get submitted values,but the result is always the same**"GET / HTTP/1.1" 200 -**
#app.route('/login',methods=['POST','GET'])
def login():
name=request.form['usename']
password=request.form['password']
form_data=request.form.get('usename')
print name,password,form_data
return render_template('login.html')
And I try visiting /login ,it shows Bad Request.But when it is modified to such,it's ok.It seems my request statement block is incorrect.
#app.route('/login',methods=['POST','GET'])
def login():
return render_template('login.html')
It's because of form action change the
action="{{url_for('index')}}"
Your form does not post actually and you are try to get values. And don't forget to add a view function named index or you can use instead login instead index
i guess you are trying to get those values from login.html file. If it is so you have to use something like this
#app.route('/login',methods = ['GET','POST'])
def login():
if request.method =='POST':
name=request.form['usename']
password=request.form['password']
form_data=request.form.get('usename')
print name,password,form_data
return render_template('login.html')
try leaving the action field emtpy.
<form class="form" action="" method="POST">
leaving it empty will post to the same location where the form was downloaded from, which I guess is your use case here.
[1] Is it a good practice to use an empty URL for a HTML form's action attribute? (action="")
Related
This question already has answers here:
Sending data from HTML form to a Python script in Flask
(2 answers)
Closed 1 year ago.
I have been working with flask for a long while, but after a break from it, I cant seem to figure out what's wrong here.
index.html:
<input name="linkHolder" type="url" class="defaultTextBox advancedSearchTextBox link" placeholder="http://www.youtube.com">
<form method="POST" action="/button">
<input class="btn" type="submit">Go</input>
</form>
main.py:
#app.route('/button', methods=["GET", "POST"])
def button():
if request.method == "POST":
dlink = request.form.get("linkHolder")
print(dlink)
return render_template("index.html", dlink=dlink)
I'm sorry if its a simple answer but my end goal here is to load the link typed by the user, print said link, and then reload the page. What am I doing wrong?
In your index.html, your <form> tag does not include the linkHolder input.
Do the following:
<form method="POST" action="/button">
<input name="linkHolder" type="url" class="defaultTextBox advancedSearchTextBox link" placeholder="http://www.youtube.com">
<input class="btn" type="submit">Go</input>
</form>
You might also need an if statement in main.py that actually renders the page
#app.route('/button', methods=["GET", "POST"])
def button():
if request.method == "GET":
return render_template("index.html")
if request.method == "POST":
dlink = request.form.get("linkHolder")
print(dlink)
return render_template("index.html", dlink=dlink)
You need a form with the name
Also, your tag </input> input doesn't have any closing tag you should be using button tag
<form method="POST" action="/button">
<input type="text" name="linkHolder">
<button class="btn" type="submit">Go</button>
</form>
I am trying to extract text from the following HTML code:
#app.route("/", methods=['GET', 'POST'])
def home():
if request.method == 'POST':
H_desiderata = float(request.form.get('H_desiderata')) #THIS CAUSES THE ERROR
return render_template('form1.html')
HTML below:
<body>
<h2>Brioche Recipe</h2>
<form>
<div class="grid-container">
<div class="grid-item">
<label class="text" for="H_desiderata">
H_desiderata:
</label><be>
<input type="number" id="H_desiderata" name="H_desiderata1"
value={{val_H_desiderata}} min="1" max="99" step="1"><br>
Before putting it into a grid it worked:
old working code:
<form>
<label for="H_desiderata">H_desiderata:</label><br>
<input type="number" id="H_desiderata" name="H_desiderata"
value={{val_H_desiderata}} min="1" max="99" step="1"><br>
How should I adapt request.form to return the value within the input box?
There is so much wrong with your code, but let's start with this:
request.form is empty when request.method == "GET. So. request.form['H_desiderata'] will give a key error.
Move that to the POST section of your view. Also, use request.form.get('H_desiderata', -9999999) in case it's not defined.
UPDATE:
OK, now try:
if request.method == 'POST':
print(request.form)
print(request.form.get('H_desiderata'))
print(float(request.form.get('H_desiderata')))
H_desiderata = float(request.form.get('H_desiderata'))
Then, you are going to want:
return render_template('form1.html', val_H_desiderata=H_desiderata)
UPDATE2:
Your <form> tag is malformed. Try:
<form action="/" method="post">
UPDATE3:
You change the name of the input, so change to: request.form.get('H_desiderata1')
I've looked around but can't seem to find an answer. I've an html form with radio button options in it. I'm trying to append them to the flask url when the results are posted based on the user input on the html page.
Here is my html page:
<form class="form-search" id="formdata" action="{{url_for('users')}}" method="post">
<label><font size="4">Select option:</font></label>
<div class="labeltext btn-group" data-toggle="buttons">
<label class="btn btn-primary active">
<input type="radio" name="radioOptions" id="option1" value="Option1" checked> Option1 </label>
<label class="btn btn-primary">
<input type="radio" name="radioOptions" id="Option2" value="Option2"> Option2 </label>
</div>
</form>
My Flask View:
#app.route('/users/<selectOption>', methods=['GET', 'POST'])
def users(selectOption):
if request.method == 'POST':
radioOptions = request.form['radioOptions']
return redirect (url_for('users', selectOption=selectOption))
return render_template('users.html')
I'm ending up with error
TypeError: users() takes exactly 1 argument (0 given)
Unsure what's going wrong from my end. I'm trying to make my url something look like below:
localhost:8080/users?radioOptions=Option1
TypeError: users() takes exactly 1 argument (0 given)
The above error you get explains it all. In the following code :
if request.method == 'POST':
radioOptions = request.form['radioOptions']
return redirect (url_for('users', selectOption=selectOption))
You redirect to users while submitting the radio option.The users expects an argument which you have not provided yet ,i.e it is changeable and that is why you are getting this error.Plus you are also not using your radioOptions value which you retrieve from this line
selectOption = request.form['radioOptions'] #I have changed radioOptions to selectOption
The correct and cleaner way would be to define another function which renders your template and call it then in your redirect call , something like this :
#app.route('/users', methods=['GET', 'POST'])
def users():
if request.method == 'POST':
selectOption = request.form['radioOptions']
return redirect (url_for('call_selected', selectOption=selectOption))
return render_template('users.html')
#app.route('/<selectOption>', methods=['GET', 'POST'])
def call_selected(selectOption):
return render_template(selectOption)
I have a form that you need to fill out using a POST request, but I want to the result to be a redirection to various pages on my site. Sometimes I want the user to be redirected to a profile page, sometimes to a purchase page.
So I put the redirect URI in the GET params of the URL of the form page that POSTs:
/form/?redirect_uri=/payments/
The url is correct upon landing on the forms page, with the appropriate redirect_uri. However, when I fill out the form and POST, Django doesn't seem to think there are any params in the GET request.
How can I get those params from the URL out on a POST request?
EDIT:
def form_view(request):
if request.method == "POST":
# Do stuff with form validation here
redirect_uri = "/home/"
if "redirect_uri" in request.GET:
redirect_uri = request.GET['redirect_uri']
if redirect_uri == request.path:
# avoid loops
redirect_uri = "/home/"
return redirect(redirect_uri)
This form page is loaded by accessing this url:
/form/?redirect_uri=/payments/
Form:
<form action="/form/" method="POST" class="wizard-form" enctype="application/x-www-form-urlencoded" autocomplete="off">
{% csrf_token %}
<fieldset class="form-group">
<label for="email">Email address</label>
<input name="email" type="text" class="form-control" id="email" placeholder="Enter email or username" required>
</fieldset>
<button type="submit" class="btn btn-primary">Go</button>
</form>
Your form has to be modified as follows:
<form action="/form/?redirect_uri={{ request.GET.redirect_url}}"
method="POST" class="wizard-form"
enctype="application/x-www-form-urlencoded" autocomplete="off">
Permit me to also suggest a slight optimization to your view
def form_view(request):
if request.method == "POST":
# Do stuff with form validation here
redirect_uri = request.GET.get('redirect_uri',"/home/")
if "redirect_uri" == request.path:
# avoid loops
redirect_uri = "/home/"
return redirect(redirect_uri)
In the POST request - i.e. when you submit the form - the url will be what you specified in the 'action' attribute in the form. If the parameters you require are not there, your view will not get them.
So either update your forms's action attribute to have these parameters or alternatively you can add thin in the form itself (as hidden inputs).
In GET request you will get attributes from url that you see in the browser.
The documentation for Flask-login talks about handling a "next" URL. The idea seems to be:
User goes to /secret
User is redirect to a login page (e.g. /login)
After a successful login, the user is redirected back to /secret
The only semi-full example using Flask-login that I've found is https://gist.github.com/bkdinoop/6698956 . It's helpful, but since it doesn't include the HTML template files, I'm seeing if I can recreate them as an self-training exercise.
Here's a simplified version of the /secret and /login section:
#app.route("/secret")
#fresh_login_required
def secret():
return render_template("secret.html")
#app.route("/login", methods=["GET", "POST"])
def login():
<...login-checking code omitted...>
if user_is_logged_in:
flash("Logged in!")
return redirect(request.args.get("next") or url_for("index"))
else:
flash("Sorry, but you could not log in.")
return render_template("login.html")
And here's login.html:
<form name="loginform" action="{{ url_for('login') }}" method="POST">
Username: <input type="text" name="username" size="30" /><br />
Password: <input type="password" name="password" size="30" /><br />
<input type="submit" value="Login" /><br />
Now, when the user visits /secret, he gets redirected to /login?next=%2Fsecret . So far, so good - the "next" parameter is in the query string.
However when the user submits the login form, he is redirected back to the index page, not back to the /secret URL.
I'm guessing the reason is because the "next' parameter, which was available on the incoming URL, is not incorporated into the login form and is therefore not being passed as a variable when the form is processed. But what's the right way to solve this?
One solution seems to work - change the <form> tag from
<form name="loginform" action="{{ url_for('login') }}" method="POST">
to:
<form name="loginform" method="POST">
With the "action" attribute removed, the browser (at least Firefox 45 on Windows) automatically uses the current URL, causing it to inherit the ?next=%2Fsecret query string, which successfully sends it on to the form processing handler.
But is omitting the "action" form attribute and letting the browser fill it in the right solution? Does it work across all browsers and platforms?
Or does Flask or Flask-login intend for this to be handled in a different way?
If you need to specify a different action attribute in your form you can't use the next parameter provided by Flask-Login. I'd recommend anyways to put the endpoint instead of the url into the url parameter since it is easier to validate. Here's some code from the application I'm working on, maybe this can help you.
Overwrite Flask-Login's unauthorized handler to use the endpoint instead of the url in the next parameter:
#login_manager.unauthorized_handler
def handle_needs_login():
flash("You have to be logged in to access this page.")
return redirect(url_for('account.login', next=request.endpoint))
Use request.endpoint in your own URLs too:
{# login form #}
<form action="{{ url_for('account.login', next=request.endpoint) }}" method="post">
...
</form>
Redirect to the endpoint in the next parameter if it exists and is valid, else redirect to a fallback.
def redirect_dest(fallback):
dest = request.args.get('next')
try:
dest_url = url_for(dest)
except:
return redirect(fallback)
return redirect(dest_url)
#app.route("/login", methods=["GET", "POST"])
def login():
...
if user_is_logged_in:
flash("Logged in!")
return redirect_dest(fallback=url_for('general.index'))
else:
flash("Sorry, but you could not log in.")
return render_template("login.html")
#timakro provides a neat solution.
If you want to handle a dynamic link such as
index/<user>
then using url_for(request.endpoint,**request.view_args) instead because request.endpoint will not contain the dynamic vairable info:
#login_manager.unauthorized_handler
def handle_needs_login():
flash("You have to be logged in to access this page.")
#instead of using request.path to prevent Open Redirect Vulnerability
next=url_for(request.endpoint,**request.view_args)
return redirect(url_for('account.login', next=next))
the following code shall be changed to:
def redirect_dest(home):
dest_url = request.args.get('next')
if not dest_url:
dest_url = url_for(home)
return redirect(dest_url)
#app.route("/login", methods=["GET", "POST"])
def login():
...
if user_is_logged_in:
flash("Logged in!")
return redirect_dest(home=anyViewFunctionYouWantToSendUser)
else:
flash("Sorry, but you could not log in.")
return render_template("login.html")
Just in case someone is trying to pass through the "next" URL with Flask-Login but with Flask_Restful, the workaround I've been using is passing the "next" argument from the GET method to the POST method. With flask_restful the "next_page" argument is set to "None" after clicking on the Login Button in the login.html
login.html
...
<!-- next_page came from "render_template(next_page=request.args.get('next') ...)" in the get() function -->
<!-- And also from render_template('login.html', next_page=next_page) in the post() function -->
<form action="{{ url_for('login', next=next_page) }}" method="POST" >
<div class="field">
<div class="control">
<input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
</div>
</div>
<div class="field">
<div class="control">
<input class="input is-large" type="password" name="password" placeholder="Your Password">
</div>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" name="remember_me">
Remember me
</label>
</div>
<button class="button is-block is-info is-large is-fullwidth">Login</button>
</form>
...
auth.py
class Login(Resource):
def get(self):
if current_user.is_authenticated:
return redirect(url_for('home'))
headers = {'Content-Type': 'text/html'}
#1 --> # Here I pass the "next_page" to login.html
return make_response(render_template('login.html', next_page=request.args.get('next')), 200, headers)
def post(self):
#2 --> # After the user clicks the login button, I retrieve the next_page saved in the GET method
next_page = request.args.get('next')
if current_user.is_authenticated:
return redirect(url_for('home'))
# Check if account exists in the db
existing_account = Account.objects(email=request.form.get('email')).first()
# Only redirects when the URL is relative, which ensures that the redirect
# stays within the same site as the application.
if existing_account:
if existing_account.check_password(request.form.get('password')):
login_user(existing_account, remember=request.form.get('remember_me'))
if not next_page or url_parse(next_page).netloc != '':
return redirect(url_for('home'))
#3 --> # Here I use the retrieved next_page argument
return redirect(url_for(next_page))
# Account not recognized
flash('Please check your login details and try again.')
headers = {'Content-Type': 'text/html'}
#4 --> # I also pass the "next_page" here in case the user-provided data is wrong
return make_response(render_template('login.html', next_page=next_page), 200, headers)
Out of all the above answers I didn't find anything helpful for me.
But what I found, I will share with you..
In login.html just add the below code
<input
type="hidden"
name="next"
value="{{ request.args.get('next', '') }}"
/>
And login definition changes as follows
#app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
next_url = request.form.get("next")
if username in users and users[username][1] == password:
session["username"] = username
if next_url:
return redirect(next_url)
return redirect(url_for("profile"))
return render_template("login.html")
And This worked perfectly for me...
Thank you ...
Simple Example
#app.route('/login', methods=['GET', 'POST'])
def login():
// do your stuff
next_page = request.form.get('next_page')
# next_page either be 'http://localhost:5000/None or 'http://localhost:5000/some_endpoints
return redirect(next_page) if 'None' not in next_page else redirect(url_for('default_action'))
Note
as Mentioned in Flask documentation
don't forget to pass next_url in html
<input type="hidden" value="{{ request.args.get('next') }}" name="next_page" id="next_page"/>
This is what worked for me, this is an addition to what #timakro and #Kurumi Tokisaki has provided in an earlier post.
#login_manager.unauthorized_handler
def handle_needs_login():
return redirect(url_for('login', next_page=request.endpoint))
#app.route('/login/<next_page>', methods=['GET', 'POST'])
def login(next_page):
if current_user.is_authenticated:
return redirect(url_for(next_page))
if is_a_successfull_login():
redirect(url_for(next_page))