Flask wtforms doesn't show validation errors (eg. when password dont match).
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length, Email, ValidationError, EqualTo, Regexp
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=5, message='Name length must be between %(min)d')]), Regexp("^[A-Za-z][A-Za-z0-9_.]*$", 0, "Username must have")
password = PasswordField('Password', validators=[DataRequired(), Length(min=8, message='Password should be at least %(min)d characters long')])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(message='*Required'), EqualTo('password', message='Both password fields must be equal!')])
email = StringField('Email', validators=[DataRequired(), Email()])
register = SubmitField('Register')
respective snippet from registration.html
<div class = "input-group mb-3">
{{form.confirm_password.label(class="form control table")}}
{{form.confirm_password(class="form-control form-control-lg", id="floatingPassword", placeholder="Confirm Password")}}
</div>
{% for error in form.password.errors %}
<div class="alert alert-danger input-group" role="alert">
<span style="color: red;">{{ error }}</span>
</div>
{% endfor %}
and snippet from route function views.py
#custodian_view.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(request.form)
if request.method == 'POST':
if form.validate_on_submit:
user = Account(email=form.email.data, username=form.username.data, password=form.password.data)
db.session.add(user)
db.session.commit()
Please, advice how can I fix this problem
If the passwords don't match, the error message will be sent via form.confirm_password.errors.
So you have to change this line:
{% for error in form.password.errors %}
into this:
{% for error in form.confirm_password.errors %}
Related
When I try to click on login button it always execute the invalid credentials instead of redirect to the index page.. What I did is that in database create table name signup and wants to validate all the data from that table.. Here signup_data function is works well but in login_data cannot authenticate the user.
Models.py
from django.db import models
class signup(models.Model):
username = models.CharField(max_length=10)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
email = models.EmailField()
password = models.CharField(max_length=10)
Forms.py
from django.forms import ModelForm
from . models import signup
from django import forms
class signupform(ModelForm):
username= forms.CharField(max_length=10,widget=forms.TextInput(attrs={'class':'form-control'}))
first_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=20,widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(max_length=20,widget=forms.EmailInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=10,widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = signup
fields = '__all__'
Views.py
from django.shortcuts import render,redirect
from . forms import signupform
from . models import signup
from django.contrib import messages
from django.contrib.auth import login,authenticate
def index(response):
return render(response,'login_module/index.html')
def signup_data(response):
if response.method == 'POST':
form = signupform(response.POST)
if form.is_valid():
username = form.cleaned_data['username']
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
if signup.objects.filter(username=username).exists():
# messages.add_message(response,messages.WARNING,'Username is already taken')
messages.error(response,'Username is already taken')
return redirect('signup')
elif signup.objects.filter(email=email).exists():
messages.error(response,'Email is already taken')
# messages.add_message(response,messages.WARNING,'Email is already taken')
return redirect('signup')
else:
register_instance = signup(username=username, first_name=first_name, last_name=last_name, email=email, password=password)
register_instance.save()
messages.success(response,'Registered Successfull')
return redirect('signup')
else:
form = signupform()
return render(response,'login_module/signup.html',{'form':form, 'message': messages})
def login_data(request):
form = signupform(request.POST or None)
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
return redirect('index')
else:
messages.error(request,'Invalid Credentials')
return redirect('login')
else:
return render(request,'login_module/login.html',{'form':form, 'message': messages})
Login.html
{% extends 'login_module/base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12 text-center mt-50">
<h1>Login Page</h1>
</div>
</div>
<div class="row">
<div class="col-md-4 offset-md-4 ">
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group rounded-top">
{{ form.username.label_tag }} {{ form.username }}
</div>
<div class="form-group rounded-top">
{{ form.password.label_tag }} {{ form.password }}
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Login</button>
</div>
</form>
</div>
</div>
<div class="text-center mt-50">
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger" role="alert">
{{ message }}
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}
Login Page
As far as I can tell you are creating a signup object when signing up, but when trying to login with authenticate django is looking for the generic User model. You have to create a User in the database rather than a signup object to use authenticate.
I am trying to create a registration page in Django and to check fields validation. I wanna set a custom validation error message to the email field. Can you help me, please?
Here is the view.py:
from django.shortcuts import render
from django.http import HttpResponse, request
from django.db import connection
from django.contrib.auth.decorators import login_required
import pyodbc
def newUser(request):
form = NewUserFrom(request.POST or None)
if not form.is_valid():
context = {'frmNewUser':form}
return render(request,'login/newuser.html', context)
return render(request, "login/welcome.html")
Here is the forms.py:
from ctypes import alignment
from email import message
from urllib import request
from django import forms
class NewUserFrom(forms.Form):
error_css_class = 'error'
username = forms.CharField(max_length=50, widget=forms.TextInput, label="Username")
password = forms.CharField(widget=forms.PasswordInput, label="Password")
confirm_password = forms.CharField(label="Confirm password", widget=forms.PasswordInput)
name = forms.CharField(max_length=50, widget=forms.TextInput, label="Name")
email = forms.EmailField(max_length=50, widget=forms.EmailInput, label="Email")
def clean_password(self):
cleaned_data = super().clean()
pwd = cleaned_data.get('password')
cof_pwd = cleaned_data.get('confirm_password')
# if pwd and cof_pwd:
if pwd != cof_pwd:
raise forms.ValidationError('Password is not match.')
return cleaned_data
def clean(self):
cleaned_data = super(NewUserFrom,self).clean()
email = cleaned_data.get('email')
if email.strip() == "".strip():
# self.add_error('email','Email is reqiered.')
raise forms.ValidationError('Email is reqiered.')
else:
fistPart, secPart = str(email).split('#')
raise forms.ValidationError('Email error.')
Here is the NewUser.html:
{% block content %}
<form method="POST">
{% csrf_token %}
<table>
{{frmNewUser.as_table}}
{% for field in frmNewUser.fields %}
{% if field.errors %}
{% for error in field.errors %}
<p style="color: red;">{{error}}</p>
{% endfor %}
{% endif %}
{% endfor %}
</table>
<input type="submit" name="Save" value="Save" colspan=2>
</form>
{% endblock content %}
You havn't mentioned against what conditions you want to validate the email. Most of the checks for a normal email shall be done by django in-build validators since you are using forms.EmailField. But if you want to do further checks, then you can create another clean method specially for the email field. Just an example to get you started.
def clean_email(self):
email = self.cleaned_data.get('email')
domain = email.split('#')[1]
if (domain == 'gmail') or (domain == 'yahoo'):
raise forms.ValidationError('Please use your official email id.')
return email
I am new to Django. I am trying to make a simple form to match the password. However, when I enter different passwords and press the Save button I get a cleared form instead of showing the validation error.
Here newuser.html:
{% block content %}
<form method="POST">
{% csrf_token %}
<table>
{{frmNewUser.as_table}}
{% for error in frmNewUser.password.errors %} {% comment %} I tried frmNewUser.non_field_errors too {% endcomment %}
<p>{{error}}</p>
{% endfor %}
</table>
<input type="submit" name="Save" value="Save" colspan=2>
</form>
{% endblock content %}
Here forms.py:
class NewUserFrom(forms.Form):
username = forms.CharField(max_length=50, widget=forms.TextInput)
password = forms.CharField(widget=forms.PasswordInput)
confirm_password = forms.CharField(label="Confirm password", widget=forms.PasswordInput)
name = forms.CharField(max_length=50, widget=forms.TextInput)
email = forms.EmailField(max_length=50, widget=forms.EmailInput)
def clean(self):
cleaned_data = super().clean()
pwd = cleaned_data.get('password')
cof_pwd = cleaned_data.get('confirm_password')
if pwd and cof_pwd:
if pwd != cof_pwd:
raise forms.ValidationError('Password is not match.')
return super().clean()
Here views.py:
from django.shortcuts import render
from django.http import HttpResponse, request
from django.db import connection
from django.contrib.auth.decorators import login_required
import pyodbc
from .forms import NewUserFrom
def newUser(request):
form = NewUserFrom(request.POST)
if not form.is_valid():
return render(request,'login/newuser.html', {'frmNewUser':NewUserFrom})
return render(request, "login/welcome.html")
Try following this article, it helped when i had a similar problem
in the newUser function
def newUser(request):
form = NewUserFrom(request.POST)
if not form.is_valid():
return render(request,'login/newuser.html', {'frmNewUser':NewUserFrom})
return render(request, "login/welcome.html")
the return value in the if statement should be changed from {'frmNewUser':NewUserFrom}) to {'frmNewUser':form})
My views-
from django.shortcuts import render, redirect
from .AuthForms import registerUserForm
from django.contrib import messages
from django.contrib.auth import login, authenticate
def registerUsers(request):
if request.method == 'POST':
ucf = registerUserForm(request.POST)
if ucf.is_valid():
ucf.save()
new_user = authenticate(username = ucf.cleaned_data['username'], password = ucf.cleaned_data['password1'])
login(request, new_user)
return redirect('content')
else:
ucf = registerUserForm()
return render(request, 'LoginAndSignUp/SignUpPage.html', {'ucf': ucf})
My form -
I have extended the usercreationform
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm , PasswordResetForm
from django import forms
class registerUserForm(UserCreationForm):
email = forms.EmailField(widget = forms.EmailInput(attrs={'placeholder':'Email', 'autocomplete':'off'}))
username = forms.CharField(widget= forms.TextInput(attrs={'placeholder':'Username','autocomplete':'off',}))
password1 = forms.CharField(widget= forms.PasswordInput(attrs={'placeholder':'Password'}))
password2 = None
class meta:
model = User
fields = ['username', 'email', 'password1']
class userLoginForm(AuthenticationForm):
username = forms.CharField(widget= forms.TextInput(attrs={'placeholder':'Username','autocomplete':'off'}))
password = forms.CharField(widget= forms.PasswordInput(attrs={'placeholder':'Password'}))
class userPasswordResetEmailForm(PasswordResetForm):
email = forms.EmailField(widget = forms.EmailInput(attrs={'placeholder':'Enter your email', 'autocomplete':'off',}))
class Meta:
model = User
fields = '__all__'
Here is my template. I suppose everything is correct but still its not saving the email
<form novalidate action="" method="post">
{%csrf_token%}
<div class="fieldWrapper">
{{ucf.email.errors}}
{{ucf.email}}
</div>
<div class="fieldWrapper">
{{ucf.username.errors}}
{{ucf.username}}
</div>
<div class="fieldWrapper">
{{ucf.password1.errors}}
{{ucf.password1}}
</div>
<div style="margin-bottom: 4%;">
<span class="director">Already with us? Log In</span>
<div class="director">
<i class="fa fa-compass"></i> Explore anonymously
</div>
</div>
<button class="primaryButton" type="submit">Sign Up</button>
</form>
The email field is not saving the email to database wherease the username and password is correctly being saved. Someone please help
Your code seems to be fine. I recreated your project and it works as intended. username, password and email are saved to the auth_user table. This is what mine looks like:
urls.py
urlpatterns = [
// other urls
path('users/', register_users, name='create_user')
]
views.py
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from users.forms import RegisterUserForm
def register_users(request):
if request.method == 'POST':
ucf = RegisterUserForm(request.POST)
if ucf.is_valid():
ucf.save()
new_user = authenticate(username=ucf.cleaned_data['username'], password=ucf.cleaned_data['password1'])
login(request, new_user)
return redirect('content')
else:
ucf = RegisterUserForm()
return render(request, 'users/sign_up_page.html', {'ucf': ucf})
forms.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
class RegisterUserForm(UserCreationForm):
email = forms.EmailField(widget=forms.EmailInput(attrs={'placeholder': 'Email', 'autocomplete': 'off'}))
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Username', 'autocomplete': 'off'}))
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
password2 = None
class Meta:
model = User
fields = ['username', 'email', 'password1']
sign_up_page.html
<form novalidate action="" method="post">
{% csrf_token %}
<div class="fieldWrapper">
{{ ucf.email.errors }}
{{ ucf.email }}
</div>
<div class="fieldWrapper">
{{ ucf.username.errors }}
{{ ucf.username }}
</div>
<div class="fieldWrapper">
{{ ucf.password1.errors }}
{{ ucf.password1 }}
</div>
<div style="margin-bottom: 4%;">
{# <span class="director">Already with us? Log In</span>#}
<div class="director">
{# <i class="fa fa-compass"></i> Explore anonymously#}
</div>
</div>
<button class="primaryButton" type="submit">Sign Up</button>
</form>
Everytime I submit my form on '/signup' view, form.validate_on_submit() in my views.py throws the error below:
TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given
The stack trace is pretty long and I don't see anything immediately obvious. I have no idea why it is doing this. I followed the Flask-WTF docs for validating forms.
EDIT: Here is the stack trace I am seeing.
views.py
from myapp import app
from flask import render_template, redirect
from forms import RegistrationForm
#app.route('/', methods=['POST', 'GET'])
#app.route('/signup', methods=['POST', 'GET'])
def signup():
form = RegistrationForm()
if form.validate_on_submit():
# Redirect to Dash Board
return redirect('/dashboard')
return render_template("signup.html", form=form)
#app.route('/login')
def login():
return "<h1>Login</h1>"
#app.route('/dashboard')
def dashboard():
return "<h1>Dashboard</h1>"
forms.py
from flask_wtf import FlaskForm
from wtforms import TextField, PasswordField
from wtforms.validators import InputRequired, Email, Length
class RegistrationForm(FlaskForm):
username = TextField('username', validators=[InputRequired(), Length(min=4, max=30)])
email = TextField('email', validators=[InputRequired(), Email, Length(max=25)])
password = PasswordField('password', validators=[InputRequired(), Length(min=8, max=80)])
class LoginForm(FlaskForm):
username = TextField('username', validators=[InputRequired(), Length(min=4, max=30)])
password = PasswordField('password', validators=[InputRequired(), Length(min=8, max=80)])
signup.html
{% extends "base.html" %}
{% block content %}
<h1>Sign Up</h1>
<form method="POST" action="/signup">
{{ form.hidden_tag() }}
<p>Username:</p>
{{ form.username() }}
<p>Email:</p>
{{ form.email() }}
<p>Password:</p>
{{ form.password() }}
<br/>
<br/>
<button type="Submit" value="submit" name="submit">Submit</button>
</form>
{% endblock %}
I figured it out! In forms.py, my RegistrationForm's email attribute should read:
email = TextField('email', validators=[InputRequired(), Email(), Length(max=25)])
I forgot the darn parenthesis for the Email parameter.