Sanic Form Validation Failing Silently - python

Hey guys I am using Sanic with WTForms and Sanic-WTF. I have this code for my SignUpForm:
class SignUpForm(SanicForm):
email = EmailField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(),
Length(min=3, max=25), EqualTo('confirm_password', message='Passwords must match.')])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired()])
I also have this as my validation for my validation in a Class Based View.
async def post(self, request):
form = SignUpForm(request)
email = form.email.data
print(email)
email_exists = await unique_db(email)
print(form.errors)
print ('Form validated: {}, Email Exists: {}'.format(form.validate_on_submit(), email_exists))
if form.validate_on_submit() and email_exists == False:
print('Validated')
await app.db.user_details.update_one({'user':'details'},{'$set': data}, upsert=True)
return json({'success':True})
return template('signup.html', form=form)
I have no idea what is going on. I have also tried doing form.validate()
My SignUp Form is
<form name="SignupForm" style="padding-top: 50px;" method="post">
{{ form.csrf_token }}
<div class="row justify-content-center">
<div class="col-lg-8 col-md-10 col-sm-12">
<div class="card">
<div class="card-body">
<h3 class="card-title">Sign up</h3>
{{ macros.render_field(form.email, label_visible=true, placeholder='Email', type='email') }}
<small id="passwordHelpBlock" class="form-text text-muted">Your email must be in the form name#example.com</small>
{{ macros.render_field(form.password, label_visible=true, placeholder='Password', type='password') }}
{{ macros.render_field(form.confirm_password, label_visible=true, placeholder='Confirm Password', type='password') }}
<button type="submit" class="btn btn-success" id="login-submit-button">Submit</button>
</div>
<div class="card-footer text-muted text-center">
Already have an account? Log in
</div>
</div>
</div>
</div>
</form>

Ok so their seems to be a bug in SanicForm, because when I changed my SignUpForm class to inherit from Form (the generic WTForm form class) it worked fine.

Related

submit button is not working in django form using crispy

I have a contact form in Django, and I use crispy in my template, but in both the Class base view and Function base view, my submit button is not working, and I have no errors.
here is my fbv code. I also tried it with cbv
my template is using jquery,bootstrap,moment.js
here is my code:
models.py
class ContactUs(models.Model):
fullname = models.CharField(max_length=150, verbose_name="Full Name")
email = models.EmailField(max_length=150, verbose_name="Email")
message = models.TextField(verbose_name="Message")
is_read = models.BooleanField(default=False)
class Meta:
verbose_name = "contact us"
verbose_name_plural = "Messages"
forms.py:
class CreateContactForm(forms.Form):
fullname = forms.CharField(widget=forms.TextInput(attrs={"placeholder": "Full Name"}),
validators=[
validators.MaxLengthValidator(150,
"Your name should be less than 150 character")
],
)
email = forms.EmailField(widget=forms.EmailInput(attrs={"placeholder": "Email address"}),
validators=[
validators.MaxLengthValidator(150,
"Your email should be less than 150 character")
],
)
message = forms.CharField(widget=forms.Textarea(attrs={"placeholder": "Your Message"}))
views.py:
def contact_page(request):
contact_form = CreateContactForm(request.POST or None)
if contact_form.is_valid():
fullname = contact_form.cleaned_data.get('fullname')
email = contact_form.cleaned_data.get('email')
message = contact_form.cleaned_data.get('message')
ContactUs.objects.create(fullname=fullname, email=email, message=message, is_read=False)
# todo : show user a success message
contact_form = CreateContactForm(request.POST or None)
context = {"contact_form": contact_form}
return render(request, 'contact_page.html', context)
Template:
<form id="contact-form" class="contact-form" data-toggle="validator" novalidate="true" method="post" action="">
{% csrf_token %}
<div class="row">
<div class="form-group col-12 col-md-6">
{{ contact_form.fullname|as_crispy_field }} {% for error in contact_form.fullname.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
<div class="form-group col-12 col-md-6">
{{ contact_form.email|as_crispy_field }} {% for error in contact_form.email.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
<div class="form-group col-12 col-md-12">
{{ contact_form.message|as_crispy_field }} {% for error in contact_form.message.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 order-2 order-md-1 text-center text-md-left">
<div id="validator-contact" class="hidden"></div>
</div>
<div class="col-12 col-md-6 order-1 order-md-2 text-right">
<button type="submit" name="submit" class="btn"><i class="font-icon icon-send"></i> Send Message</button>
</div>
</div>
</form>
Try adding "save" to the submit button class.
Also your contact_page view does nothing after saving the contact data to the db. If you'll do a pop-up confirmation in JS you don't need to instantiate contact_form the second time. Or if you want to redirect the user:
def contact_page(request):
contact_form = CreateContactForm(request.POST or None)
if contact_form.is_valid():
fullname = contact_form.cleaned_data.get('fullname')
email = contact_form.cleaned_data.get('email')
message = contact_form.cleaned_data.get('message')
ContactUs.objects.create(
fullname=fullname,
email=email,
message=message,
is_read=False
)
return redirect('some-view')
context = {"contact_form": contact_form}
return render(request, 'contact_page.html', context)

Django 3.0 Forms: Form Errors are not showing onto template

###I have model named Publisher in models.py file.###
###And based on this model, a modelForm has made, called "RegistrationForm".###
###Which renders form on registration.html template.###
<br /> <br />**This is code of registration.html**
<pre><code>
```
<body>
<div class="container">
{% load my_filters %}
<div class="row">
<div class="col-md-6 offset-md-3">
{% if registered %}
<h1>Thank you for registering!</h1>
{% else %}
<h1>Register Here</h1>
<h3>Just fill out the form.</h3>
<form enctype="multipart/form-data" method="POST">
{% csrf_token %}
{{ reg_form.non_field_errors }}
<div class="fieldWrapper">
<div class="form-group">
{{ reg_form.name.errors }}
<label for="{{ reg_form.name.id_for_label }}" >Name:</label>
{{ reg_form.name|addclass:'form-control' }}
</div>
</div>
<div class="fieldWrapper">
<div class="form-group">
{{ reg_form.email.errors }}
<label for="{{ reg_form.email.id_for_label }}">Email:</label>
{{ reg_form.email|addclass:'form-control' }}
</div>
</div>
<div class="fieldWrapper">
<div class="form-group">
{{ reg_form.contact.errors }}
<label for="{{ reg_form.contact.id_for_label }}">Contact:</label>
{{ reg_form.contact|addclass:'form-control' }}
</div>
</div>
<div class="fieldWrapper">
<div class="form-group">
{{ reg_form.password.errors }}
<label for="{{ reg_form.password.id_for_label }}">Password:
</label>
{{ reg_form.password|addclass:'form-control' }}
</div>
</div>
<div class="fieldWrapper">
<div class="form-group">
{{ reg_form.confirm_password.errors }}
<label for="{{ reg_form.confirm_password.id_for_label }}">Confirm
Password:</label>
{{ reg_form.confirm_password|addclass:'form-control' }}
</div>
</div>
<input type="submit" name="" value="Register">
</form>
{% endif %}
</div>
</div>
</div>
</body>
```
</code></pre>
### I am NOT using crispy forms just manually rendering Django forms and using manual template tag to add classes to fields.
**This is the template tag in used to add classes to form fields**
<code><pre>
```
#register.filter(name='addclass')
def addclass(value, arg):
return value.as_widget(attrs={'class': arg})
```
</code></pre>
**This is the model in models.py**
<code><pre>
```
class Publisher(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField('Name', max_length=50)
email = models.EmailField('Email', unique=True)
password = models.CharField('Password', max_length=50)
contact = models.CharField('Contact #', max_length=16, unique=True, validators=[
RegexValidator(
regex=r'^\+?1?\d{9,15}$',
message="Phone number must be entered in the format '+123456789'. Up to 15 digits allowed."
),
],)
def __str__(self):
return self.name
```
</code></pre>
**This is the form in forms.py file**
<code><pre>
```
class RegistrationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = Publisher
fields = ('name','email','contact','password')
def clean(self):
cleaned_data = super(RegistrationForm, self).clean()
password = cleaned_data.get("password")
confirm_password = cleaned_data.get("confirm_password")
if password != confirm_password:
raise forms.ValidationError(
"password and confirm_password does not match"
)
```
</code></pre>
**This is the view in views.py file**
<code><pre>
```
def registration(request):
registered = False
if request.method == 'POST':
reg_form = RegistrationForm(data=request.POST)
if reg_form.is_valid():
user = reg_form.save()
user.save()
registered = True
else:
#Now issue is this printing statement working fine and printing errors on console.But
#errors are not showing on template.
print(reg_form.errors)
else:
reg_form = RegistrationForm()
return render(request, 'seller/registration.html',
{'reg_form': RegistrationForm,
'registered': registered
})
```
</code></pre>
I have seen all the stack overflow and tried many thing but none of them help me TO GET MY ERRORS ON FORM TEMPLATE (Though errors like password doesn't match and contact number error etc are getting printed on django console as defined in else statement of views.py file).
After filling form with wrong data pressing "submit" button it refreshes the form rather showing errors. And after filling form with with right data user gets registered (It shows "Thank you for registering" as defined in template). I know there must be silly thing I am doing or missing. Kindly let me know.

form.validate_on_submit() from flask_wtf FlaskForm not working

I am trying to submit a form using wtforms. I can't get it to validate. I also tried using {{ form.csrf_token }} and it still did not work.
app.config['SECRET_KEY'] = 'thisisthesecretkey'
class LoginForm(FlaskForm):
username = StringField('username', validators=[
InputRequired(), Length(min=4, max=15)])
password = PasswordField('password', validators=[
InputRequired(), Length(min=8, max=80)])
remember_me = BooleanField('remember me')
#app.route('/login', methods=['GET', 'POST'])
def login():
form = forms.LoginForm()
if form.validate_on_submit():
return 'worked'
return render_template('login.html', form=form)
my jinja:
<form class="form-signin" action="/login" method="POST">
{{ form.hidden_tag() }}
{{ wtf.form_field(form.username) }}
{{ wtf.form_field(form.password) }}
{{ wtf.form_field(form.remember_me) }}
</form>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted text-center">© 2020</p>
Your action dictates the form will post to /login. I think you want action="/register"
I had an and before the form, I placed them inside and then added a to the form fields, this solved the issue, it now looks like this:
<form class="form-signin-heading" method="POST" action="/login">
<div class="text-center mb-4">
<img class="mb-4" src="/static/logo.jpg" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Heading1</h1>
</div>
<div class="container">
{{ form.hidden_tag() }}
{{ wtf.quick_form(form) }}
<button class="btn btn-lg btn-primary btn-block" type="submit">Log in</button>
</div>
</form>

Django validation error messages only showing in admin page

I have a SignUp form that interacts with Django's user model to create new users. If password fields match, the user is successfully created and logged in. If password fields do not match, the user is not created, so I guess validation is working. But somehow, a validation error message is not shown, the form page is just rendered again. When I go to Django's admin page, the error messages pop up there! Why is it not popping in my template?!
This is my form:
class SignUpForm(forms.ModelForm):
password = forms.CharField(max_length=20, required=True, widget=forms.TextInput(attrs={'placeholder':'Password', 'class':'form-control', 'type':'password'}),)
password2 = forms.CharField(max_length=20, required=True, widget=forms.TextInput(attrs={'placeholder':'Confirm Password', 'class':'form-control', 'type':'password'}),)
class Meta:
model = User
widgets = {'first_name': forms.TextInput(attrs={'placeholder':'First Name', 'class':'form-control'}),
'last_name': forms.TextInput(attrs={'placeholder':'Last Name', 'class':'form-control'}),
'email': forms.TextInput(attrs={'placeholder':'Email', 'class':'form-control', 'type':'email'}),
'username': forms.TextInput(attrs={'placeholder':'Username', 'class':'form-control'}),
'password': forms.TextInput(attrs={'placeholder':'Password', 'class':'form-control', 'type':'password'})
}
fields = {'first_name', 'last_name', 'email', 'username', 'password'}
def clean(self):
cleaned_data = super(SignUpForm, self).clean()
password = cleaned_data.get('password')
password2 = cleaned_data.get('password2')
if password != password2:
raise forms.ValidationError('Passwords do not match!')
And this is my view:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
form.save()
user = authenticate(username=username, password=password)
login(request, user)
messages.add_message(request, messages.SUCCESS, 'Account created successfully!')
return HttpResponseRedirect('/')
else:
messages.add_message(request, messages.ERROR, "There's an error in the form! Please fill it again.")
return render(request, 'form/register.html', {'form': form})
else:
form = SignUpForm()
return render(request, 'form/register.html', {'form': form})
And this is my template:
<div class="login-box-body">
{% block login_form %}
<form method="POST">
{% csrf_token %}
{% if form.errors %}
{% for error in field.errors %}
<p class="login-box-msg" style="color: red;">{{ error }}</p>
{% endfor %}
{% endif %}
<div class="form-group has-feedback">
{{form.first_name}}
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.last_name}}
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.email}}
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.username}}
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.password}}
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.password2}}
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-8">
<button type="button" class="btn btn-default" onclick="window.location.href='{% url 'manager:login' %}'">Voltar</button>
</div>
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">Criar Conta</button>
</div>
</div>
</form>
{% endblock login_form %}
What am I doing wrong?
Okay, I managed to work it out, at least as a temporary solution! Daniel was right, there was a typo in my template, but it was showing "_ all _" as the error message, not sure why.
Since the password fields were the only ones I was using raise forms.ValidationError function, then the error message was only to be shown in case the passwords wasn't matching.
So I just wrote the error message I wanted directly in my template! Like this:
<form method="POST">
{% csrf_token %}
{% if form.errors %}
<p class="login-box-msg" style="color: red; font-weight: bold;">Passwords do not match!</p>
{% endif %}
It doesn't work the way I wanted, but it does the job!

django form is valid() fails

I am trying to create a registration form using django, when I submit my form the is valid() function fails and I am not sure why. I have my registration and login page all on one html page, although, I have called all the field names different names, eg login_username.
forms.py
class SignUpForm(forms.Form):
username = forms.CharField(label='Username', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter Username'}))
conUsername = forms.CharField(label='Confirm Username', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Confirm Username'}))
firstName = forms.CharField(label='First Name', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter Firstname'}))
lastName = forms.CharField(label='Last Name', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter LastName'}))
email = forms.CharField(label='Email', max_length=220,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter Email','type':'email'}))
conEmail = forms.CharField(label='Confirm Email', max_length=220,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Confirm Email','type':'email'}))
password = forms.CharField(label="Confirm Password", max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','type':'password','placeholder':'Enter Password'}))
conPassword = forms.CharField(label="Confirm Password", max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','type':'password','placeholder':'Confirm Password'}))
views.py
def SignUp(request):
regForm = SignUpForm()
form = LoginForm()
if request.method == 'POST':
if regForm.is_valid():
username = regForm.cleaned_data('username')
print username
confirm_username = regForm.cleaned_data('conUsername')
first_name = regForm.cleaned_data('firstName')
last_name = regForm.cleaned_data('lastName')
email = regForm.cleaned_data('email')
confirm_email = regForm.cleaned_data('conEmail')
password = regForm.cleaned_data('password')
confirm_password = regForm.cleaned_data('conPassword')
#try:
#user = User.objects.get(username=request.POST['username'])
#return render(request, 'index.html',{'error_message':'username must be unique'})
#except User.DoesNotExist:
#user = User.objects.create_user(request.POST['username'], password=request.POST['password'])
#login(request, user)
#return render(request, 'index.html')
else:
return render(request,'index.html',{'username_error':'usernames didnt match','form':form,'regForm':regForm})
else:
return render(request, 'index.html',{'form':form,'regForm':regForm})
index.html
<form class="regForm" method="POST" action="{% url 'signup' %}">
{% csrf_token %}
{{username_error }}
<div class="row">
<div class="col-md-2 col-md-offset-8">
<div class="form-group">
{{regForm.error_message.username}}
{{ regForm.username }}
</div>
</div>
<div class="col-md-2 ">
<div class="form-group">
{{error_message.conUsername}}
{{ regForm.conUsername }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-2 col-md-offset-8">
<div class="form-group">
{{ regForm.firstName }}
</div>
</div>
<div class="col-md-2">
<div class="form-group">
{{ regForm.lastName }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<div class="form-group">
{{ regForm.email }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<div class="form-group">
{{ regForm.conEmail }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-2 col-md-offset-8">
<div class="form-group">
{{ regForm.password }}
</div>
</div>
<div class="col-md-2">
<div class="form-group">
{{ regForm.conPassword }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-3 col-md-offset-9">
<div class="form-group">
<button type="submit" id="regBtn" class="btn btn-default">Submit</button>
</div>
</div>
</div>
</form>
Right now your form is always empty and therefore invalid. You forgot to add the request POST content to the form.
def SignUp(request):
# ...
if request.method == 'POST':
regForm = SignupForm(request.POST) # form needs content
if regForm.is_valid():
# ...
If you get stuck when calling .is_valid(), you can print(regForm.errors) to see what's up.
You have two main problems. Firstly, you are never passing the POST data to the form, so it can never be valid.
Secondly, for some reason you are ignoring everything that the form could tell you about why it is not valid, and always returning "usernames didn't match". What's more, you're not even doing anything to compare usernames, so that error message will never be accurate.
You should rework your view to follow the pattern as described in the documentation:
def SignUp(request):
if request.method == 'POST':
regForm = SignUpForm(request.POST)
if regForm.is_valid():
...
return redirect(somewhere)
else:
regForm = SignUpForm()
return render(request, 'index.html', {'regForm':regForm})
and in your template make sure you include {{ form.errors }} to show what the validation failures are.

Categories

Resources