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().
Related
I`m wrirting site on Django and I need to make a system for registration and authorization of work peepers, for this I use the Django AbstractUser model, registration works well, but authorization does not work, and the authenticate method returns None
Here is my JobseekerRegsiterInfo model:
class JobseekerRegisterInfo(AbstractUser):
username = first_name = last_name = None
id = models.BigAutoField(primary_key=True)
phone_number = PhoneNumberField()
email = models.EmailField(unique=True)
full_name = models.CharField(max_length=120)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['phone_number', 'full_name', 'hashed_password']
def __str__(self):
return self.full_name
My login form:
class JobseekerLoginForm(forms.Form):
email = forms.EmailField(label='Введіть ваш Email: ',
widget=forms.EmailInput(attrs={'class': 'form-control'}))
password = forms.CharField(label='Ваш пароль: ',
widget=forms.PasswordInput(attrs={'class': 'form-control'}))
def clean_email(self):
email = self.cleaned_data['email']
# if not select_field_value_from_model(JobseekerRegisterInfo, 'email', email):
if not JobseekerRegisterInfo.objects.filter(email=email):
raise forms.ValidationError('Неправильно введені email або пароль')
return email
and view function:
def jobseeker_login_view(request):
title = 'Авторизація'
context = {'title': title}
if request.method == 'POST':
form = JobseekerLoginForm(request.POST)
context['form'] = form
if form.is_valid():
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user = authenticate(request, email=email, password=password)
print(generate_password_hash(password))
if user:
print(user)
else:
print('USER IS NONE')
else:
form_errors = form.errors.as_data()
custom_error = custom_error_service(form_errors)
context['list_first_error'] = custom_error
else:
form = JobseekerLoginForm()
context['form'] = form
return render(request, template_name='jobseeker/jobseeker_login.html', context=context)
But only USER IS NONE is displayed in the console, no matter what I do
Tell me, please, how to use authenticate correctly in my case
So...
My main intention is that when a user edits his/her account and changes the email, the system has to change all the other info except email and send an email to the new email (inputted by the user) with a confirmation link. And once clicked, the system has to redirect the user to another page and change the email for that account. Please tell me how I can do this.
my view:
class NormalUserEditView(generic.UpdateView):
form_class = EditProfileFormNormal
template_name = 'authentication/edit_normalprofile.html'
success_url = reverse_lazy('profile')
def form_valid(self, form):
messages.success(self.request, f'Account Edit: Successful')
return super().form_valid(form)
def get_object(self):
return self.request.user
For the email thing I was referring to this view:
def register_user(request):
if request.method == "POST":
form = RegisterUserForm(request.POST)
if form.is_valid():
myuser = User.objects.create_user(
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['password1'],
)
myuser.is_active = False
myuser.save()
# "Thank You For Registering" Email
subject = "Welcome To some website"
body = "Hello " + myuser.first_name + "!\n" + "Thank you for registering to some website. Your account has been registered. However, it has not been activated. We have sent you another email that contains a link. In order to activate your account you must click on that link. The email will be sent shortly. \nNOTE: If you have not created an account in some website, please ignore this email. \n \nsome website."
from_email = settings.EMAIL_HOST_USER
to_list = [myuser.email]
send_mail(subject, body, from_email, to_list, fail_silently=True)
# Confirm Email
current_site = get_current_site(request)
email_subject = "Confirm Your Email - some website"
email_message = render_to_string('authentication/email_confirmation.html', {
'name': myuser.first_name,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(myuser.pk)),
'token': generate_token.make_token(myuser),
})
email = EmailMessage(
email_subject,
email_message,
settings.EMAIL_HOST_USER,
[myuser.email],
)
email.fail_silently=True
email.send()
messages.success(request, ("Registration: Successful!"))
return redirect('confirm-address-page')
else:
form = RegisterUserForm()
return render(request, 'authentication/register.html', {
'form':form,
})
this for token generating:
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from six import text_type
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self,user,timestamp):
return (
text_type(user.pk) + text_type(timestamp)
# text_type(user.profile.signup_confirmation)
)
generate_token = TokenGenerator()
this for the forms:
class RegisterUserForm(UserCreationForm):
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
first_name = forms.CharField(max_length=50, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=50, widget=forms.TextInput(attrs={'class': 'form-control'}))
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2')
def __init__(self, *args, **kwargs):
super(RegisterUserForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['class'] = 'form-control'
self.fields['password1'].widget.attrs['class'] = 'form-control'
self.fields['password2'].widget.attrs['class'] = 'form-control'
email_confirmation.html :
{% autoescape off %}
Welcome to Some Website
Hello {{ name }}!
Please Confirm your email by clicking on the following link:
Confirmation Link:
http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}
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
How to enable users to use other languages such as Chinese in username field using the usercreation form?
The methods I have tried:
modify the regex field of username field, failed
What it tells me: the validation is not with the field, but the user model itself
encode the incoming input using encode("utf-8")
What it tells me: the data i
client side utf transform...
This is the code in view:
def register_user(request):
currentPath = request.POST.get('currentPath', '')
currentPath = currentPath.replace("invalid/", "").replace("registered/", "")
username=request.POST.get('email')
password=request.POST.get('password1')
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
if "log" in currentPath:
return HttpResponseRedirect(currentPath)
else:
return HttpResponseRedirect('/register_success')
elif "log" in currentPath:
return HttpResponseRedirect(currentPath + "registered")
else:
form = MyRegistrationForm()
form.fields['password1'].label = "密码"
form.fields['password2'].label = "再次输入密码"
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('register.html', args)
I think the form.save() is where the problem come from... that the validator automatically validates the field no matter what and chinese characters fail the validation.
And the following is the customized registration form, I have tried to override regex field with an username field but it doesn't work.
my_default_errors = {
'required': '这个格子是必填的',
'invalid': '请输入符合要求的值',
}
class MyRegistrationForm(UserCreationForm):
error_messages = {
'duplicate_username': ("同样的用户名已经被注册了"),
'password_mismatch': ("和上次输入的不一样,请重新输入!"),
}
# this variable defines a field in the customized form, not a model datafield
username = forms.RegexField(label = "用户名(其他所有人可见,请使用英文)", required=True, max_length=30,
regex=r'^[\w.#+-\/\\]+$',
error_messages=my_default_errors,)
email = forms.EmailField(label="邮箱(用于登录)" ,required=True, max_length = 75, error_messages = my_default_errors, )
password1 = forms.CharField(label= "密码", required=True, widget=forms.PasswordInput, error_messages = my_default_errors,)
password2 = forms.CharField(label= "请再次输入", required=True, widget=forms.PasswordInput, error_messages = my_default_errors,)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def clean_email(self):
email = self.cleaned_data["email"]
try:
user = User.objects.get(email=email)
raise forms.ValidationError("这个邮箱地址已被注册,是否忘记了密码?")
except User.DoesNotExist:
return email
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.email = self.cleaned_data["email"]
user.is_active = True # change to false if using email activation
if commit:
user.save()
return user
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