I have a form that I created with WTForms (using the Flask-WTF extension) and am using a SelectMultipleField to generate two groups of dynamic checkboxes. I'm having an issue where if I check any of the boxes from the Orientation group the form does not validate, but also does not give me any validation errors. I'm also not using any validators on that field. If I submit it without checking anything from the Orientation group, it will submit just fine. If I select any of the checkboxes from the Subreddit group, which is built almost identically, the form submits just fine.
Here is my form class:
class RegistrationForm(Form):
email = StringField('Email', validators=[Required(), Length(1,64),
Email()])
username = StringField('Username', validators=[
Required(), Length(1, 64), Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0,
'Usernames must have only letters, '
'numbers, dots or underscores')])
password = PasswordField('Password', validators=[
Required(), EqualTo('password2', message='Passwords must match.')])
password2 = PasswordField('Confirm password', validators=[Required()])
sex = SelectField('Sex', choices=[('M', 'Male'), ('F', 'Female'), ('T', 'Transgendered')], validators=[Required()])
min_age = IntegerField('Minimum Age', validators=[Required()])
max_age = IntegerField('Maximum Age', validators=[Required()])
city = StringField('City', validators=[Required()])
state = SelectField('State', validators=[Required()])
location_alias = StringField('Location Aliases')
location_radius = IntegerField('Radius of matches (in miles)',
validators=[Required(), NumberRange(min=0,
max=100,
message="Radius must be between 0-100 miles.")])
orientation = SelectMultipleField('Orientation (posts you want to see)',
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False))
subreddits = SelectMultipleField('Subreddits',
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False))
def validate_min_age(self, field):
if field.data < 18:
raise ValidationError("Minimum age must be at least 18.")
def validate_email(self, field):
if User.query.filter_by(email=field.data).first():
raise ValidationError("We already have a user with this email address.")
def validate_username(self, field):
if User.query.filter_by(username=field.data).first():
raise ValidationError("We already have a user with this username.")
# Data for dynamic checkboxes needs to be initialized when the form is used
def __init__(self, *args, **kwargs):
Form.__init__(self, *args, **kwargs)
self.state.choices = [(s.state, s.state) for s in State.query.all()]
self.orientation.choices = [(o.orientation, o.orientation) for o in Orientation.query.all()]
self.subreddits.choices = [(s.subreddit, s.subreddit) for s in Subreddit.query.all()]
And here is my view that loads this form and calls validate_on_submit():
#auth.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
# get or create the location object
l = Location.query.filter_by(city=form.city.data, state=form.state.data).first()
if not l:
l = Location(city=form.city.data, state=form.state.data)
db.session.add(l)
db.session.commit()
# add the locaton alias
for location_alias in form.location_alias.data.split('*'):
if location_alias:
add_location_alias(l, location_alias)
# get the orientations
orientations = []
for o in form.orientation.data:
orientation = Orientation.query.filter_by(orientation=o).first()
if orientation:
orientations.append(orientation)
# add the user
u = User(
email=form.email.data,
username=form.username.data,
password=form.password.data,
sex=form.sex.data,
min_age=form.min_age.data,
max_age=form.max_age.data,
location_id=l.id,
location_radius=form.location_radius.data,
orientations=orientations,
subreddits=[]
)
db.session.add(u)
db.session.commit()
print 'User has been added successfully.'
return redirect(url_for('main.index'))
print 'Form failed validation.'
return render_template('auth/register.html', form=form)
Related
I have registration form where users can put their first name, last name, email and password.
I'm trying to get that email and split it to get the domain and check my database if that email already registered, but i'm not able to split the data, no matter what I change I keep getting different errors.
forms.py
class RegistrationForm(FlaskForm):
first_name = StringField(
"First Name", validators=[DataRequired(), Length(min=2, max=20)]
)
last_name = StringField(
"Last Name", validators=[DataRequired(), Length(min=2, max=20)]
)
email = StringField("Email", validators=[DataRequired(), Email()])
password = PasswordField("Password", validators=[DataRequired()])
confirm_password = PasswordField(
"Confirm Password", validators=[DataRequired(), EqualTo("password")]
)
submit = SubmitField("Sign Up")
# Here i'm trying to split the email so I can use the domain.
domain = email.split("#")[1]
def validate_email(self, email, domain):
user_email = User.query.filter_by(email=email.data).first()
org_domain = Organization.query.filter_by(domain=domain.data).first()
if user_email:
raise ValidationError("That email is taken. Please choose a different one.")
elif org_domain:
raise ValidationError(
"Your domain is managed by someone else, please contact your administrator. If you need help please contact our support"
)
routes.py
#users.route("/register", methods=["GET", "POST"])
def register():
if current_user.is_authenticated:
return redirect(url_for("main.dashboard"))
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode(
"utf-8"
)
organization = Organization(
domain=form.email.data.split("#")[1],
)
db.session.add(organization)
db.session.commit()
admin = User(
first_name=form.first_name.data,
last_name=form.last_name.data,
display_name=form.first_name.data + " " + form.last_name.data,
email=form.email.data,
password=hashed_password,
org_id=organization.id,
)
db.session.add(admin)
db.session.commit()
flash("Your account has been created! You are now able to log in", "success")
return redirect(url_for("users.login"))
return render_template("users/register.html", title="Register", form=form)
I got it to work by splitting it under def validate_email(self, email):
domain = str(email).split("#")[1]
domain = domain.split('"')[0]
I made a clean_email function in my forms.py to check if the email the person is signing up with is part of a registered school.
This is the form:
class StudentRegister(UserCreationForm):
email = forms.EmailField(required = True)
def __init__(self, *args, **kwargs):
super(StudentRegister, self).__init__(*args, **kwargs)
self.fields['email'].widget.attrs['placeholder'] = 'example#example.com'
self.fields['first_name'].widget.attrs['placeholder'] = 'First Name'
self.fields['last_name'].widget.attrs['placeholder'] = 'Last Name'
self.fields['password1'].widget.attrs['placeholder'] = 'Password'
self.fields['password2'].widget.attrs['placeholder'] = 'Password'
class Meta:
model = get_user_model()
fields = (
'email',
'first_name',
'last_name',
'password1',
'password2'
)
def clean_email(self):
email = self.cleaned_data.get('email')
email = email.split('#')[1]
try:
school = School.objects.get(email_domain = email)
except ObjectDoesNotExist:
raise forms.ValidationError('School not found, check your email')
return email
def save(self):
user = super(StudentRegister, self).save()
student = Student(user = user)
student.save()
return user, student
This is the view for the student registration:
def student_registration(request):
#Student Registration
if request.method == 'POST':
form = StudentRegister(request.POST)
#Gets school object from email domain.
email = form['email'].value().split('#')[1]
try:
school = School.objects.get(email_domain = email)
except ObjectDoesNotExist:
pass
if form.is_valid() and school:
user, Student = form.save()
Student.school = school
Student.save()
user.groups.add(Group.objects.get(name='Student'))
#user.is_active to stop users logging in without confirming their emails
user.is_active = False
user.save()
#Sends confirmation link.
send_confirmation_email(request, user)
args = {'email': user.email,
'link': user.Student.school.email_website,}
return render(request, 'email/token_sent.html', args)
else:
args = {'form': form,}
return render(request, 'users/students.html', args)
else:
form = StudentRegister()
args = {'form': form,}
return render(request, 'users/students.html', args)
The error that appears on the form is "Enter a valid email address." even if I enter in a valid email.
Any ideas what the problem may be?
In clean_email method you override original email with domain. Change yout code to this:
def clean_email(self):
original_email = self.cleaned_data.get('email')
email = original_email.split('#')[1]
try:
school = School.objects.get(email_domain = email)
except ObjectDoesNotExist:
raise forms.ValidationError('School not found, check your email')
return original_email
I have a form that allows the user to change their email address. The form also prompts the user to enter their current password as part of the form.
The form does change the email address, but the user can enter any value for the password and the email address is changed.
For some reason, the password is not being checked and confirmed before the email is changed.
I cannot figure out what I have done.
Here is my form code:
class EmailChangeForm(forms.Form):
error_messages = {
'email_mismatch': _("The two e-mail address fields do not match."),
'email_inuse': _("This e-mail address cannot be used. Please select a different e-mail address."),
'password_incorrect': _("Incorrect password."),
}
current_password = forms.CharField(
label=_("Current Password"),
widget=forms.PasswordInput,
required=True
)
new_email1 = forms.EmailField(
label=_("New E-mail Address"),
max_length=254,
required=True
)
new_email2 = forms.EmailField(
label=_("Confirm New E-mail Address"),
max_length=254,
required=True
)
def __init__(self, user, *args, **kwargs):
self.user = user
super(EmailChangeForm, self).__init__(*args, **kwargs)
def clean_current_password(self):
"""
Validates that the password field is correct.
"""
current_password = self.cleaned_data["current_password"]
if not self.user.check_password(current_password):
raise forms.ValidationError(self.error_messages['password_incorrect'], code='password_incorrect',)
return current_password
def clean_new_email1(self):
"""
Prevents an e-mail address that is already registered from being registered by a different user.
"""
email1 = self.cleaned_data.get('new_email1')
if User.objects.filter(email=email1).count() > 0:
raise forms.ValidationError(self.error_messages['email_inuse'], code='email_inuse',)
return email1
def clean_new_email2(self):
"""
Validates that the confirm e-mail address's match.
"""
email1 = self.cleaned_data.get('new_email1')
email2 = self.cleaned_data.get('new_email2')
if email1 and email2:
if email1 != email2:
raise forms.ValidationError(self.error_messages['email_mismatch'], code='email_mismatch',)
return email2
def save(self, commit=True):
self.user.email = self.cleaned_data['new_email1']
if commit:
self.user.save()
return self.user
Here is my views.py code:
#login_required
def email_change(request):
language_versions = get_language_versions(user=request.user)
if request.method == 'GET':
form = EmailChangeForm(user=request.user)
elif request.method == 'POST':
form = EmailChangeForm(user=request.user, data=request.POST)
if form.is_valid():
form.save()
messages.success(request, _('successfully updated.'))
return redirect('email_change')
return render(request, 'user_settings/email_change.html', {
'display_default_language': display_default_language(request.user),
'form': form,
'languages': LANGUAGES,
'language_versions': language_versions,
'language_versions_num': len(language_versions),
})
Your clean_password() method should be called clean_current_password().
I want to create my own form for user createion of django.contrib.auth.models.User in Django, but I cant find a good example. Can someone help me?
you want to create a form?
create a form say forms.py
from django.contrib.auth.models import User
from django import forms
class CreateUserForm(forms.Form):
required_css_class = 'required'
username = forms.RegexField(regex=r'^[\w.#+-]+$',
max_length=30,
label="Username",
error_messages={'invalid': "This value may contain only letters, numbers and #/./+/-/_ characters."})
email = forms.EmailField(label="E-mail")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
def clean_username(self):
existing = User.objects.filter(username__iexact=self.cleaned_data['username'])
if existing.exists():
raise forms.ValidationError("A user with that username already exists.")
else:
return self.cleaned_data['username']
def clean_email(self):
#if you want unique email address. else delete this function
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError("This email address is already in use. Please supply a different email address.")
return self.cleaned_data['email']
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The two password fields didn't match.")
return self.cleaned_data
create a view say views.py
def create_inactive_user(request):
if request.method=='POST':
frm=CreateUserForm(request.POST)
if frm.is_valid():
username, email, password = frm.cleaned_data['username'], frm.cleaned_data['email'], frm.cleaned_data['password1']
new_user = User.objects.create_user(username, email, password)
new_user.is_active = True # if you want to set active
new_user.save()
else:
frm=CreateUserForm()
return render(request,'<templatepath>',{'form'=frm})
it is better to use django-registration
userform
class UserForm(forms.ModelForm):
confirm_password = forms.CharField(label="Confirm Password",widget=forms.PasswordInput(attrs = {'placeholder': 'Confirm Password','class':'required'}))
phone = forms.CharField(max_length = 15,widget = forms.TextInput(attrs = {'placeholder':'Enter mobile no. ','class':'required number'}))
profession = forms.CharField(max_length= 50,widget = forms.Select(choices = PROFESSION_CHOICES,attrs = {'class':'required'}))
email = forms.EmailField(label='Email address',max_length = 75,widget = forms.TextInput(attrs={'placeholder':'Enter a valid email.','class':'required email'}))
sex = forms.CharField(max_length = 20,label="I am :",widget=forms.Select(choices=SEX_CHOICES,attrs = {'class':'required'}))
password = forms.CharField(label="Password",widget=forms.PasswordInput(attrs = {'placeholder': 'Password','class':'required'}))
first_name = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Please enter your real name.','class':'required alphabets'}))
last_name = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Enter last name.','class':'required alphabets'}))
def clean_first_name(self):
first_name = self.cleaned_data['first_name']
if first_name == '':
raise forms.ValidationError("This field is required.")
def clean_phone(self):
phone = self.cleaned_data['phone']
if phone == '':
raise forms.ValidationError("This field is required.")
def clean_last_name(self):
last_name = self.cleaned_data['last_name']
if last_name == '':
raise forms.ValidationError("This field is required.")
def clean_email(self):
email = self.cleaned_data.get("email")
try:
user = User.objects.get(email = email)
raise forms.ValidationError("Email already in use.")
except User.DoesNotExist:
return email
def clean_profession(self):
profession = self.cleaned_data['profession']
if profession == "":
raise forms.ValidationError("Select a valid option.")
def clean_sex(self):
sex = self.cleaned_data['sex']
if sex == "":
raise forms.ValidationError("Select a valid option.")
def save(self,*args,**kw):
user = super(UserForm,self).save(*args,**kw)
user.set_password(self.cleaned_data.get("password"))
user.first_name = self.cleaned_data.get("first_name")
user.last_name = self.cleaned_data.get("last_name")
user.email = self.cleaned_data.get("email")
user.save()
user.get_profile().phone = self.cleaned_data.get('phone')
user.get_profile().location = self.cleaned_data.get('location')
user.get_profile().profession = self.cleaned_data.get('profession')
user.get_profile().sex = self.cleaned_data.get('sex')
return user
class Meta:
model = User
fields = ('username','email','password','confirm_password','first_name','last_name','sex','phone','profession')
widgets = {
'password': forms.PasswordInput(),
}
user registration view
def register_user(request):
if request.POST:
data = request.POST.copy()
data["username"] = 'user'
rform = UserForm(data)
#form = UserProfileForm()
if rform.is_valid():
try:
user = rform.save()
user.username = "user"+str(user.id)
user.save()
user = authenticate(username = user.username,password=user.password)
#register user
login(request,user)
return redirect(index)
except:
print "Unexpected error"
raise
else:
# submit the same form again.
form = LoginForm();
sform = LoginForm()
return render_to_response('register.html',{'rform':rform,'form':form,'sform':sform},context_instance = RequestContext(request))
else:
rform = UserForm()
#form = UserProfileForm()
form = LoginForm()
sform = LoginForm()
return render_to_response('register.html',{'rform':rform,'form':form,'sform':sform},context_instance = RequestContext(request))
error
IntegrityError at /accounts/register/
auth_user.first_name may not be NULL
doubt
When i was using the normal user authentication , everything was working perfectly but when i am using it with email authentication , it gives me the above error ,
how do i get past this error , please help , and also how do i make the email field unique as in how do i add index to this field , please help
Your custom field cleaning methods (clean_*) do not return the cleaned value. From the form validation docs: https://docs.djangoproject.com/en/1.4/ref/forms/validation/
Just like the
general field clean() method, above, this method should return the
cleaned data, regardless of whether it changed anything or not.
clean_first_name does not have a return which is the same as returning None and the reason why Django is trying to insert a NULL for this field.