Why Reload button sending POST request ?, Flask Python - python

I have created a sign-up page with username and password form inputs that send a POST request upon entering and I wish to send it to my database
But I see that even on clicking the reload button, a POST request is sent.
This is my python-flask code for the route
#app.route('/signup',methods=["GET","POST"])
def signup():
return render_template('signup.htm')
if request.method=="POST":
password = request.form['password']
Is there an option to specify that clicking the reload button SENDS ONLY A GET REQUEST?

First of all in your code, nothing will run after the return statement so the if statement wont run.
Secondly you should separate your functions. By this I mean that you should have a separate function for rendering the page and for handling the form response
Such as:
#app.route('/signup',methods=["GET"])
def signup():
return render_template('signup.htm')
#app.route('/submitsignup',methods=["POST"])
password = request.form['password']
return 'Form submitted'

Related

Python - Flask - Stop page from re-submitting a post request

How can I stop Flask from re-adding form data to database on refresh?
My form.html sends data to approved.html like so:
if request.method == 'POST':
element = db_name(request.form.get('element'))
db.session.add(element)
db.session.commit()
else:
return redirect(url_for('home'))
return render_template('approved.html', current=element)
This so I can display the data from the form and let the user know entry has been added. But the problem is whenever I refresh approved.html which displays the form data, another copy of this entry is added to the database.
This happens because the browser stores the state of the last request and refreshing will re-submit the form, leading to another entry in your database. This is also why it's normal practice to redirect on the server-side after successful form submission. See Preventing POST on reloading a form and here
What you need to do is to successfully handle a successful form request and then redirect the user to a fresh state.
So something like this
return redirect(url_for('success'))
can be added instead of the render_template function which will then be redirected to the assigned function; there you can call the render_template of your choice.

How to login user through all routes with flask?

I'm stuck in a loop, I have a web app, the login and signup was made using Flask on the Backend and Jinja for templating, no JS was used for these two routes, I used WTForms for form validation and Flask Login to handle login .
Now, when user login he is redirected to a dashboard, the dashboard is a single page application that use React, I send HTTP request to my API which is built in Flask (same app, but different blueprints).
The problem is that these APIs routes are avalable only for authenticated users, so I used a token system to authenticate API calls from the client to the server .
To do so, I created a request loader for my login manager, that using a token parameter in the query would decode it , get the email and password and return the respective User, otherwise if it fail it returns None
#login_manager.request_loader
def load_user(request):
if "token" in request.args:
decoded_token = base64.standard_b64decode(request.args["token"])
email = decoded_token.split(b':',1)[0]
password = decoded_token.split(b':',1)[1]
possible_user = User.select().where(User.email == email)[0]
if possible_user.password.encode() == password:
return possible_user
else:
return None
else:
return None
return None
This token is sent to the user when he login and get redirected to the dashboard :
User login successfULY
Get redirected to dashboard
Dashboard make an ajax call to "/user-data" , which is protected, this route should use current_user to encode the token and send it back to dashboard single page app to use it in further API calls .
The problem:
When I request the "/user-data" through AJAX from dashboard, current_user is empty thus, the call return a 401 unauthorized request even though the user did login, and in the login route, when I print current_user I get the current user logged in as expected . So my question is how can I keep some way to exhcange credentials between login and "user-data" route ? I tried storing the data in a session in the login route then re-use it in the '/user-data' but the session becomes empty whenever 'user-data' is called .
Here's 'user-data' route :
#auth_bp.route("/user-data")
#login_required
def user_data():
# Return Base 64 encode username:password to use in API calls!
print("Current user")
print(current_user)
print(session)
code = base64.standard_b64encode(current_user.email.encode() + b':' + current_user.password.encode())
print(base64.standard_b64decode(code))
return code

Flask on login redirection issue

I am sending out a confirmation token to users after they register to confirm their email. The issue I have is that I cant get to the confirm method as it requires the user to login and once they go to the login method I cant work out how to direct them back to the confirm method.
Note the code is heavily based on the (very good) book 'Flask Web Development' by Grinberg 2014.
We start here with a new user signing up:
#auth.route('/signup', methods=['GET', 'POST'])
def signup():
#validate form and create user
...
token = user.generate_confirmation_token()
send_email(user.email, 'Please Confirm Email Address',
'email/confirm', user=user, token=token)
return redirect(url_for('auth.login'))
return render_template('auth/register.html', form=form)
The new user is sent and email, when the user clicks on the link in the email they are sent to this route:
#auth.route('/confirm/<token>')
#login_required
def confirm(token):
if current_user.confirmed:
return redirect(url_for('main.index'))
if current_user.confirm(token):
#do something here
else:
#message
return redirect(url_for('main.index'))
As login is required to get to the confirm end point, the user is directed here first:
#auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user is not None and user.verify_password(form.password.data):
login_user(user)
return redirect(request.args.get('next') or url_for('main.index'))
return render_template('auth/login.html', form=form)
The issue I have is that after the user logs in they are not redirected to the confirm route and I can't work out how to redirect to confirm for this case where the user is just logging in so that they can respond to the signup email link. Any ideas?
I'm also learning from this book. Though I don't know what's wrong with you, I can show some key information to you to solve your problem.
First, your test email have the URL like this.(http://127.0.0.1:5000/auth/confirm/eyJleHAiOjE0NjY0ODQwOTAsImFsZyI6IkhTMjU2IiwiaWF0IjoxNDY2NDgwNDkwfQ.eyJjb25maXJtIjo5OX0.npxbWrOYVzX2HYibnDQLNS0FuX-J9XB-TcmZZSPri-8)
Then, you click it and though the code #login_required, so you redirect to the login page, but the URL is not equal to the usual login URL. It has some thing different like this. (http://127.0.0.1:5000/auth/login?next=%2Fauth%2Fconfirm%2FeyJleHAiOjE0NjY0ODQwOTAsImFsZyI6IkhTMjU2IiwiaWF0IjoxNDY2NDgwNDkwfQ.eyJjb25maXJtIjo5OX0.npxbWrOYVzX2HYibnDQLNS0FuX-J9XB-TcmZZSPri-8)
Next, return redirect(request.args.get('next') or url_for('main.index')) this line of your code will get the next confirm URL after the key next=, and visit the confirm page.
So you can check your URL if it has some problems.
Additionally, I recommend you debug your code in pycharm because you can set breakpoint and track variables' changes. Good luck.

Url in browser not updated after call of redirect( url_for('xxx' )) in Flask with jQuery mobile

I have a very simple python program using Flask shown below. It handles a login with a popup and logout. The problem is that the url in the browser is not updated by the redirect(url_for()) call.
#app.route('/')
def index():
if not 'username' in session:
# contains a button showing a login popup form with action set to '/login'
return render_template('welcome.html')
else:
# contains a logout button with a href to '/logout'
return render_template('webapp.html')
#app.route('/login', methods=['POST'])
def login():
session['username'] = request.form['username']
return redirect(url_for('index'))
#app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('index'))
When accessing '/' the welcome page is shown. When I click on the button, the login popup is shown and its form action redirects to '/login'. This works and the login() function is called and executed. The redirect as well, but the browser doesn't update the displayed url.
So the webapp page is shown with the /logon url. When I click reload I get an error because it tries to reload /logon while it should reload '/' where it has been redirected.
The same happens with /logout. When the webapp page is shown and I click the logout button, the /logout page is loaded which executes the logout() function and redirects to index. But the url is left to logout.
If I then reload the page, it succeeds because /logout accept the GET method and then the url is updated to / as it should have been in the first place.
I have the impression it is a jQuery mobile issue, but can't find out the problem. From the python and Flask point of view it matches all login examples I could find.
Finally solved it after finishing writing the question.
The problem is caused by jQuery mobile and the missing data-url attribute.
By adding the data-url attribute in the page div the url in the browser is updated and everything works fine.
<div data-role="page" id="welcome" data-url="{{ url_for('index') }}">

Why does the login method of Flask use 'GET'?

I'm trying to learn more about Flask for a project, and I'm wondering if someone can explain to me why the sample code lists the methods 'GET' and 'POST', when it only ever tries to process a login if the request was 'POST'?
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != app.config['USERNAME']:
error = 'Invalid username'
elif request.form['password'] != app.config['PASSWORD']:
error = 'Invalid password'
else:
session['logged_in'] = True
flash('You were logged in')
return redirect(url_for('show_entries'))
# Note that nowhere do we seem to care about 'GET'...
return render_template('login.html', error=error)
GET and POST methods are both handled by your function.
When GET is used, the login form (login.html) is returned for the user to log in. This is the last line of the function.
When POST is used, the form is validated using provided login/password. After that the user is either redirected to an other page (url for show_entries) or the login form is sent another time with the related error.
You should read 'When do you use POST and when do you use GET?' for more details on why POST is used to process the login form and why GET is used to send it.
return render_template('login.html', error=error) is the handler for GET.
Think about the logic:
if request.method == 'POST':
Check Credentials, Set error method
If no credential errors return the correct redirect
if there were errors in the POST section of code render_template gets those errors, otherwise it gets the None from the beginning of the method. I assume that if error is None in render_template it probably just renders a plain ol' login form.
Note: I've never used flask, but I understand python

Categories

Resources