I have a Flask-WTF form for sign in. Apparently the form is never valid, no matter what I enter "success" is never printed. Why isn't my form validating?
class loginForm(Form):
email = EmailField('email', validators=[InputRequired("Please enter your email address."), Email("Please enter a valid email address.")])
password = PasswordField('password', validators=[InputRequired("Please enter your password.")])
#app.route('/sign-in', methods=['POST', 'GET'])
def signIn():
form = loginForm(request.form)
if form.validate_on_submit():
print 'success'
return redirect('/')
return render_template('signIn.html')
<form method="POST" action="/sign-in">
{{ form.email(placeholder='Email', class="textBox") }}
{{ form.password(placeholder='Password', class="textBox") }}
<button onclick="submit()">Sign In</button>
</form>
Flask-WTF adds a CSRF protection field. If it's not present, the CSRF validation will fail, and the form will be invalid. Use form.hidden_tag() to include any hidden fields in your form (including the CSRF field).
<form method="post">
{{ form.hidden_tag() }}
...
In general, if a form is not validating, you should check form.errors after calling validate to see what's wrong.
You don't see the error since you're not rendering that field (or rendering the errors for any fields in this case, but that wouldn't help with this issue). If you ran in a debugger and examined form.errors, you would see that there was indeed a "CSRF token missing" error.
Related
few months ago i made a website where it worked but similar code this time isn't working! it returns :
ValueError at /registration/
The User could not be created because the data didn't validate.
this is my form.py in bottom:
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]
my views:
from .form import CreateUserForm
def registrationPage(request):
form = CreateUserForm()
if request.method == "POST":
form = CreateUserForm(request.POST)
if form.is_valid:
form.save()
return redirect("login")
else:
form = CreateUserForm()
context = {"form": form}
return render(request, "store/registration.html", context)
in HTML previously i used :
{{form.errors}}
& it used to show me work on the page but not anymore
According to your comment above ("i want django to show the error messages"[if password is weak in example]), you should add this to your html page (instead than {{form.errors}}).
<div class="error-message">
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<p style="font-size: 13px;">
{{ error|escape }}
</p>
{% endfor %}
{% endif %}
</div>
Form.non_field_errors()
This method returns the list of errors from Form.errors that aren’t associated with a particular field. This includes ValidationErrors that are raised in Form.clean() and errors added using Form.add_error(None, "...").
When this error you get then do this:
You must type strong password, which is provided by Django.
password validation rules:
At least 1 digit;
At least 1 uppercase character;
At least 1 lowercase character;
At least 1 special character;
for example:
Example#4089
This error will come while confirming your password, you must enter correct password in both the fields.
you will face this error if user is already exist.
you must check exists user while creating user, if user exist, this error will come.
I have used the built-in validators, but none of them is printing a message on the page. Also, I want to create a custom validator to check duplicate username. I have written the function, as I am a beginner, I don't know how to use it. Pls resolve the problem.
from flask import Flask, app, render_template, request, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from wtforms.validators import InputRequired, EqualTo, ValidationError
app = Flask(__name__)
app.config['SECRET_KEY'] = "PQrs12t46uvvrty567"
class MyForm(FlaskForm):
username = StringField('Username', validators=[InputRequired(message="This field is required.")])
password=PasswordField('Password', validators=[InputRequired(message=("enter the password"))])
confirm_password=PasswordField('Confirm Password', validators=[EqualTo('password')])
submit = SubmitField('Register')
def isDuplicate():
appdatabase={"Alis":"Smith","Mike":"Brown","Paul":"Miller"}
form = MyForm()
for user in appdatabase:
if form.username == appdatabase[user]:
raise ValidationError("Username already exists! Please choose another one.")
#app.route('/')
def base():
form = MyForm()
return render_template('customvalidator.html', form = form)
#app.route('/submitform', methods=["GET","POST"])
def submitform():
form = MyForm()
if form.validate_on_submit():
return 'Form accepted successfully.'
else:
return 'Incorrect form data'
if __name__=="__main__":
app.run(debug=True)
HTML file
<!DOCTYPE html>
<html>
<head><title>My website</title></head>
<body>
<h1>Registration form</h1>
<form action="{{ url_for('submitform') }}" method="post">
{{ form.csrf_token }}
{{ form.username.label }}
{{ form.username }}
<ul>
{% for error in form.username.errors %}
<li style="color: red;">{{ error }} </li>
{% endfor %}
</ul>
<br>
{{ form.password.label }}
{{ form.password }} <br><br>
{{ form.confirm_password.label }}
{{ form.confirm_password }} <br><br>
{{ form.submit}}
</form>
</body>
</html>
Try changing the isDuplicate function to this:
def isDuplicate(form, field):
appdatabase={"Alis":"Smith","Mike":"Brown","Paul":"Miller"}
form = MyForm()
for user in appdatabase:
if form.username.data == appdatabase[user]:
raise ValidationError("Username already exists! Please choose another one.")
Notice the added form and field parameters to the function to allow its use as a custom validator. form.username was also changed to form.username.data to access the data of the username field. (This whole function will need to be defined before the form.)
You will then need to add this custom validator to your list of validators for the username field in your form like so:
username = StringField('Username', validators=[InputRequired(message="This field is required."),isDuplicate])
With these changes, the custom validation should work, but we still haven't solved the issue of the custom error messages. To do this, add a novalidate attribute to your HTML form tag. Adding this will disable the default validation on forms and allow you to display custom messages.
With that in place, I believe the messages still won't work because of how you are handling the form submission. When the form does not validate, you will want to display the same form template instead of showing them whether it submitted or not.
My personal opinion is that merging your two form routes will be the simplest option. Have a route define the form, check for when it gets validated or not, and then render the form template. This will enable you to keep everything together and not render a different template when you only want to display the same template with a few added error messages.
Credits:
Custom validators (check the last point)
SO question on displaying validation messages
-which led me to this one on actually how to disable the default messages.
My problem is: when an user refresh a form, the data in the Form is sent.
I have a Form with a POST request.
The user writes his name, mail and a message. If the mail is correct, the message is sent.
In my view, if the Form is valid, I add the message in my model Message.
After that I disable the "Send" button. But if the user refreshes the page, my view is called, and another row is added in my model.
I would like, when the user refreshes the page, to block the POST.
My View:
def contact(request):
form = MessageForm(request.POST or None)
if form.is_valid():
name = form.cleaned_data['name']
message = form.cleaned_data['message']
mail = form.cleaned_data['mail']
new_message = Message()
new_message.name = name
new_message.message = message
new_message.mail = mail
new_message.save()
envoi = True
return render(request, 'vautmieux/contact.html', locals())
My URL:
path('contact/', views.contact, name='contact'),
My HTML:
<form action="{% url "contact" %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col-md-6">
{{ form.name }}
{{ form.mail }}
</div>
<div class="col-md-6" >
{{ form.message }}
</div>
<button id="sendMessageButton" type="submit">ENVOYER LE MESSAGE !</button>
</div>
{% if envoi %}Votre message a bien été envoyé !{% endif %}
</form>
This is the main reason why people implement the Post/Redirect/Get pattern [wiki]. In case of a successful POST request, you should return a redirect to a URL. As a result the browser will perform a GET, and in case the browser thus performs a refresh later, it will make a GET again.
def contact(request):
if request.method == 'POST':
form = MessageForm(request.POST)
if form.is_valid():
form.save()
return redirect('some-message-successful-view')
else:
form = MessageForm()
return render(request, 'vautmieux/contact.html', {'form': form})
Here 'some-message-successful-view' needs to be replaced with the name of a view you trigger when sending a message was succesful. This can be the same view as the one defined here. I advice to use Django's message framework [Django-doc] to send a message to the user that the message has been submitted successfully.
I'm making a register page for my django (version 2.0) website, but it pretty messy to me, I'm pretty sure the bullet points and the additional information is not supposed to show up right away.
How can I make this register page look cleaner? Ie. just the username, password, and confirmation textbox, rather than all the messages.
Thanks!
Register.html
<h2>Sign up</h2>
<br>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign up</button>
</form>
Register view
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('index')
else:
form = UserCreationForm()
return render(request, 'todo/register.html', {'form': form})
There are many ways to achieve this.
Overriding the default UserCreationForm()
class MyForm(UserCreationForm):
email = forms.EmailField(required=True)
email.help_text = ''
...
In the view template instead of using {{ form.as_p }} render the form manually
<form action="" method="post">{% csrf_token %}
{{ form.username.label }}
{{ form.username }}
...
</form>
Design your custom template and map the field name to the form field name.
Hope it helps !
You did not specify where this UserCreationForm came from nor your django version, but anyway: searching django's code source it appears that those are the help_text for the various widgets / fields of the default contrib.auth.forms.UserCreationForm, so yes the "bullet points and the additional information" is actually "supposed to show up right away". And as far as I'm concerned (from a user perspective I mean) it's a good thing that it does "show up right away", so I don't have to retype username and passwords twice, thrice or more until I found out by trial/errors what the system expects (or, more often, just plain give up registering on this site).
Now if you really want to frustrate your users (and loose half of them on the way), you can of course mask all those useful informations by rendering the form manually so you have full control on which messages appear, when, where and how.
I have a Flask-WTF form for sign in. Apparently the form is never valid, no matter what I enter "success" is never printed. Why isn't my form validating?
class loginForm(Form):
email = EmailField('email', validators=[InputRequired("Please enter your email address."), Email("Please enter a valid email address.")])
password = PasswordField('password', validators=[InputRequired("Please enter your password.")])
#app.route('/sign-in', methods=['POST', 'GET'])
def signIn():
form = loginForm(request.form)
if form.validate_on_submit():
print 'success'
return redirect('/')
return render_template('signIn.html')
<form method="POST" action="/sign-in">
{{ form.email(placeholder='Email', class="textBox") }}
{{ form.password(placeholder='Password', class="textBox") }}
<button onclick="submit()">Sign In</button>
</form>
Flask-WTF adds a CSRF protection field. If it's not present, the CSRF validation will fail, and the form will be invalid. Use form.hidden_tag() to include any hidden fields in your form (including the CSRF field).
<form method="post">
{{ form.hidden_tag() }}
...
In general, if a form is not validating, you should check form.errors after calling validate to see what's wrong.
You don't see the error since you're not rendering that field (or rendering the errors for any fields in this case, but that wouldn't help with this issue). If you ran in a debugger and examined form.errors, you would see that there was indeed a "CSRF token missing" error.