I created the following form:
class ContentForm(Form):
content = StringField(u'write here' , validators=[Required()])
submit = SubmitField(u'Let them know' )
When I submit, things seem to work. However, when I refresh the page afterwards, the form is submitted again. How do I fix this?
You need to redirect after making a POST request. Otherwise, the browser will do what you're experiencing (the behavior has nothing to do with WTForms).
#app.route('/my_form', methods=['GET', 'POST']
def my_form():
form = ContentForm()
if form.validate_on_submit():
# do stuff
return redirect('my_form') # or wherever
return render_template('my_form.html', form=form)
Related
I am trying to make a web app with a login system. I want to make it so that a user can't access certain pages unless they are logged in.
What I want is that when you click to go to another page while not logged in, you get redirected to the login page and on it you get a message flash.
This is what works:
#app.route("/home", methods=['GET', 'POST'])
def home():
#some form
if not current_user.is_authenticated:
flash('You need to be logged in to access this page.', 'info')
return redirect(url_for('login'))
#rest of the code
But I would need to add all of this to other routes as well. So I created the function and added it to the routes instead:
#app.route("/home", methods=['GET', 'POST'])
def home():
#some form
require_login()
#rest of the code
def require_login():
if not current_user.is_authenticated:
flash('You need to be logged in to access this page.', 'info')
return redirect(url_for('login'))
But this does not work as I want it to. It instead redirects to the home page and then flashes the message. How do I fix this?
The problem is that the redirect(...) doesn't itself do the redirect. It returns a value to Flask telling flask that it needs to do the redirect.
In your first piece of code, you handle this correctly. You take the result of redirect(...) and return it to flask. In your second piece of code, you take the redirection returned by require_login and ignore it in home.
You might try something like:
value = require_login()
if value:
return value
You need to return the function
return require_login()
But be aware, after that u cant have code. You should create an decorator for this. There are examples online just Google "flask authorized decorator"
Your Advantage of this that u can move the auth Logic out of the Views and you can easily decorate your Views and dont have this Stuff in each View/route
I have a defined form created using FlaskForm/WTForms where I also defined the validators of the same form. I would like to know how can I validate it using the validators already defined in my form before submitting it, for example, having one button to validate the form and then another to submit the form.
I'm assuming I need to find a way to execute form.validate() from the html when a button is clicked. My approach was to create a view to only execute form.validate() and call it when a button is clicked using jQuery. However, this is not working. And I'm assuming because the form object created in the "create" view and that is passed to the HTML is not the same as the form object created in the "_validate_form" view. But I don't know what other approaches to take. I would appreciate some ideas on how could I solve this problem.
This is my FlaskForm:
class CreateTripForm(FlaskForm):
truck = SelectField('Truck', widget=CustomSelect(), validators=[selection_required], validate_choice=False)
origin = SelectField('Origin',
widget=CustomSelect(),
validators=[selection_required], validate_choice=False)
material = SelectField('Material',
widget=CustomSelect(),
validators=[selection_required], validate_choice=False)
destination = SelectField('Destination',
widget=CustomSelect(),
validators=[selection_required], validate_choice=False)
sender_comment = TextAreaField('Comment', validators=[validators.Length(max=150, message="Máximo 150 caracteres!")])
submit = SubmitField('Confirm Trip')
This is my view when form.validate_on_submit():
#trips_blueprint.route('/create', methods=['GET', 'POST'])
#login_required
def create():
form = f.CreateTripForm()
if form.validate_on_submit():
trip_dict = {
'truck_id': form.truck.data,
'material_name': form.material.data,
'origin_name': form.origin.data,
'destination_name': form.destination.data,
'sender_username': current_user.username,
'sender_comment': form.sender_comment.data
}
trip = Trip.create(**trip_dict)
return redirect(url_for('trips.create'))
return render_template('create_home.html', form=form)
This is my view to only validate form. Which is not working.
#trips_blueprint.route('/_validate_form', methods=['POST'])
def _validate_form():
print('In _validate_form!')
form = f.CreateTripForm()
if form.validate():
return jsonify(True)
This is the jQuery script I'm using to try to validate the form:
function validateForm(){
$.post( "{{url_for('trips._validate_form') }}" );
}
$('#validation_button').click(function(){
validateForm();
});
i am working on a project, and i created two modal forms on the landing page. both forms are for registration and login.
only one form seems to be coming up and the other cannot come up and thereby making it impossible for the forms to submit.
how do i achieve this challenge, that both forms can be displayed and can submit to the database respectively.
also i am a rookie i just started a few weeks ago
i have tried and all i keep getting are errors or only one form displays
#app.route('/main', methods=['GET', 'POST'])
def main():
form = Signup_Form()
forms = Login_Form()
if request.method =="GET":
return render_template('/main.html', form=form, forms=forms)
if request.method == "POST":
return render_template('main.html', form=form, forms=forms)
else:
return redirect('home.html')
i expect to see both forms display when clicked and also submit to the database when the submit button is clicked
So I'm trying to do some test cases with webtest library, the problem is that my site has access control which requires a user to login. It seems that the form post is successful, but the result do not have any cookies (that I could find at least), and the cookiejar is empty after the login.
Test setup:
class TestMyViewSuccessCondition(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
from myapp import main
settings = {'sqlalchemy.url': postgresqlURL}
app = main({}, **settings)
from webtest import TestApp
self.testapp = TestApp(app, cookiejar=CookieJar())
Test:
page = self.testapp.get('/login', status=200)
self.assertIn('Please login', page)
form = page.forms['loginForm']
form['username'] = 'user'
form['password'] = 'userpw'
result = form.submit(status=200)
# self.testapp.cookies is empty dictionary at this point
# it fails here, login page is shown again
page = self.testapp.get('/home', status=200)
result returns 200 OK, and the HTML content of the login page, after the form submit, but no redirect is happening, is that a problem? or is that working as intended? Before the any access control other form submits worked just fine. The cookies will change every time when the user clicks a link or reloads the page. I'm using session cookies. I tried to set a unsecure flag for cookies.
and the last return of the my login view:
if 'form.submitted' in request.POST:
# do stuff
return HTTPFound(location=request.route_url('home'))
I would be using the normal unittest but since unittest module looses its nuts when the view tries to do redirect, someone suggested webtest library.
Problem was that the form.submit() didn't actually mimic the basic use-case of mine, where the user clicks the submit button. In normal case the browser adds the username, password and the ('form.submitted', '') in side of the request.POST. But the form.submit() only adds the username and password, and only those that are defined in the form, so I couldn't define my own values to go with the request. (at least I didn't found out how)
Problem was solved inside of the login view. by changing the if 'form.submitted' in request.POST: -> if 'username' in request.POST and 'password' in request.POST:
Cookies are working just fine, as show above, login failed to support my test.
I'd like to know if anyone knows:
For example, I have a form that user fills in, and when he submits, the page will redirect to "thank you" page. Everything works fine. In urls.py I had this line pointing that the page exists:
url(r'^thankyou/$', 'render_form'),
But then, when I type in url mysite.com/thankyou/, the page "Thank you" appears... But I need it to appear only when I submit a form and hide it when user tries to open it directly.
Please help. Thanks in advance!
You could put something in the session in your form handling view before redirecting, and check it in the thank-you URL: if it's not there, then return a 403 error. Something like:
def form_handling_view(request):
if request.POST:
form = MyForm(request.POST)
if form.is_valid():
... handle the form ...
request.session['form_posted'] = True
return redirect('thank_you')
def thank_you(request):
if not request.session.pop('form_posted', False):
return HttpResponseForbidden('not permitted')
... render thank_you page ...
Note I'm using pop in thank_you to ensure that the key is deleted from the session no matter what.