I am trying to confirm user password in a secure way using PasswordInput() but Django seem to only allow for one PasswordInput() per form. What is the best way to implement confirm_password below:
class VerifyAccountsForm(forms.ModelForm):
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Username'}), label="")
password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Password'}), label="")
password_verify = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Verify password'}), label="")
def clean_password(self):
print self.cleaned_data
password1 = self.cleaned_data.get('password')
password2 = self.cleaned_data.get('password_verify')
if not password2:
raise forms.ValidationError("You must confirm your password")
if password1 != password2:
raise forms.ValidationError(_('Your passwords do not match'), code='invalid')
return password2
The output of clean_data is only the username and password, no password_verify.
if you use django's own usercreationform, you can have both fields, here is how I used it
form's clean_password2() function compares two password inputs and validates them too, and returns the second password.
I don't know what gives you the idea that Django only allows one password input per form. You can have as many as you like, Django won't stop you.
Note that your current code is called on validation of password, but returns the value of password_verify.
However if you're getting something you don't expect from cleaned_data, you should post the code of the clean method.
Change the def clean_password(self): to def clean_password2(self): in
the forms.py and in HTML registration form(registraton.html) write {{ form.password2.errors.as_text }} just above the password input field.
Related
In this code , if it is always displaying password does not match when I'm still giving the correct password. I'm unable to figure out exactly what's happening here! Pls help me with this.
def Guide_register(request):
if request.method == 'POST':
firstname = request.POST.get('first_name')
lastname = request.POST.get('last_name')
username = request.POST.get('username')
email = request.POST.get('email')
password1 = request.POST.get('password1')
password2 = request.POST.get('password2')
image = request.POST.get('image')
city = request.POST.get('city')
if password1 == password2:
if Guide_Register.objects.filter(username=username).exists():
messages.error(request,'Username already exists!')
return redirect('guideregister')
else:
if Guide_Register.objects.filter(email=email).exists():
messages.error(request,'Email already exists!')
return redirect('guideregister')
else:
guide = Guide_Register.objects.create(first_name=firstname,last_name=lastname,username=username,email=email,password=password1,confirm_password=password2,guide_photo=image,city=city)
messages.success(request,'You are registered successfully as Guide!')
return redirect('guidelogin')
else:
messages.error(request,'Password does not match!')
return redirect('guideregister')
else:
return render(request,'accounts/guide_register.html')
It is strongly advised to use Django forms when doing form validation, you might want to take a look at it. You would need to write a custom def clean(self, cleaned_data) function in the form class to check that password1 and password2 match, reading this section might be useful.
As for your problem, I suspect that your posted data is lacking either password1 or password2, you might want to check on the template side that you have input fields for both password1 and password2:
<input name="password1" type="password" />
<input name="password2" type="password" />
To check what is exactly being posted, you might want to debug using print(request.POST) before if password1 == password2: and check what the backend receives.
I was working with Django Forms , I was doing custom validation for a field, but encountered weird problem.
forms.py
class RegistrationForm(forms.Form):
username = forms.CharField(max_length=50)
email = forms.EmailField(required=False)
password = forms.CharField(max_length=50)
password1 = forms.CharField(max_length=50)
def clean_password(self):
password = self.cleaned_data['password']
print(self.cleaned_data) # all fields are present except password1 in cleaned Data
re_password = self.cleaned_data['password1'] #Gives Key Error here
# Do something
Here when I try to do some validation for password field in clean_password function, It gives key error for password1 field ,I don't get why that happens. I tried searching a lot but couldn't find anything relevant, about what causes this error.But then I tried making some change in code and It worked but I don't know why it worked.
modified_forms.py
class RegistrationForm(forms.Form):
username = forms.CharField(max_length=50)
email = forms.EmailField(required=False)
password1 = forms.CharField(max_length=50) #swapped position
password = forms.CharField(max_length=50)
def clean_password(self):
password = self.cleaned_data['password']
print(self.cleaned_data) # all fields are present in cleaned Data
re_password = self.cleaned_data['password1'] #Doesn't Give Key Error here
# Do something
The changes I made was I just swapped the line position of password1 and password ,that is I just changed the order of password and password1. I changed order password1 at line of password, password at position where was password1. And it solved error I don't understand this behaviour from what I know field order shouldn't effect anything. Can someone please explain what is happening here? Thanks :)
It is not weird behavior. Django forms work this way. Please look at the source code here to understand how field cleaning works for django forms. Here is a stripped down version of _clean_fields method.
def _clean_fields(self):
for name, field in self.fields.items():
# skipped
try:
# skipped
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
# skipped
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
What it does is loop over form fields, and for every field, puts its cleaned value in cleaned_data dict. If a method for cleaning field (clean_<FIELD_NAME>) is defined, it calls that method on cleaned data for that field and puts it in cleaned_data dict.
In your first case password1 comes after password. Because fields are cleaned in order, password1 is not yet cleaned when you are trying to access it in clean_password method. Which means its cleaned value is not yet present in cleaned_data dict.
In second case, you swap the position of password and password1. Now cleaning has been performed for password1 and you can access its value.
The rule of thumb is that for clean_<FIELD_NAME> method, you can only access cleaned values of those fields that are declared before that specific field.
Solution
You should do this as django does in its UserCreationForm. They check password match on second field i-e password1 should match password not vice versa (which is essentially same). Snippet with modification from here .
def clean_password1(self):
password = self.cleaned_data.get("password")
password1 = self.cleaned_data.get("password1")
if password and password1 and password != password1:
raise forms.ValidationError('Passwords do not match')
return password1
You use python. python is scripting type language and use interpreter so code will evaluate line by line
in your case you create def clean_password(self) so this method call after taking password from form in lazy evaluation. if you rename your method without swapping of password and password1 rename you method with def clean_password1(self) it work fine
forms.py
class RegistrationForm(forms.Form):
username = forms.CharField(max_length=50)
email = forms.EmailField(required=False)
password = forms.CharField(max_length=50)
password1 = forms.CharField(max_length=50)
def clean_password1(self):
password = self.cleaned_data['password']
print(self.cleaned_data) # all fields are present
re_password = self.cleaned_data['password1']
if you satisfied of my answer let me know
I think it's better practise to make separate clean methods for password and password1 fields
def clean_password(self):
password = self.cleaned_data['password']
# Do something
def clean_password1(self):
password1 = self.cleaned_data['password1']
# Do something
Or validate both in clean() method
def clean(self):
cleaned_data = super().clean()
password = cleaned_data['password']
re_password = cleaned_data['password1']
# Do something
I want to create a SINGLE form which gives the ability to the admin to create a new user with extended profile. Please note that, I don't want to use admin and registration apps.
I have extended the user with the UserProfile model. I have read all the documents related to extending user profile. But, I really don't know how to save these information.
I coded the following django form for this issue:
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField()
last_name = forms.CharField()
password1=forms.CharField(max_length=30,widget=forms.PasswordInput()) #render_value=False
password2=forms.CharField(max_length=30,widget=forms.PasswordInput())
email=forms.EmailField(required=False)
title = forms.ChoiceField(choices=TITLE_CHOICES)
def clean_username(self): # check if username dos not exist before
try:
User.objects.get(username=self.cleaned_data['username']) #get user from user model
except User.DoesNotExist :
return self.cleaned_data['username']
raise forms.ValidationError("this user exist already")
def clean(self): # check if password 1 and password2 match each other
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
raise forms.ValidationError("passwords dont match each other")
return self.cleaned_data
def save(self): # create new user
new_user=User.objects.create_user(username=self.cleaned_data['username'],
first_name=self.cleaned_data['first_name'],
last_name=self.cleaned_data['last_name'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'],
)
return new_user
Is it OK? however it gives me an error in first_name and last_name. Says django doesn't expect first_name and last_name in save() method.
create_user only supports the username, email and password arguments. First call create_user, then add the extra values to the saved object.
new_user=User.objects.create_user(self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.save()
I'm trying to implement a user registration page in Django. Seems like a simple task, but I'm getting an error I just don't understand. Here's my view:
def registration_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username = form.cleaned_data['username'],
password = form.cleaned_data['password1'],
email = form.cleaned_data['email1']
)
return HttpResponseRedirect('/register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('registration/registration_page.html', variables)
And here's my registration form:
class RegistrationForm(forms.Form):
username = forms.CharField(label = u'Username', max_length = 30, error_messages={'required': 'A username is required.'})
email1 = forms.EmailField(label = u'Email Address', error_messages={'required': 'An email address is required.'})
email2 = forms.EmailField(label = u'Email Address confirmation', error_messages={'required': 'A confirmed email address is required.'})
password1 = forms.CharField(label = u'Password', widget = forms.PasswordInput(), error_messages={'required': 'A password is required.'})
password2 = forms.CharField(label = u'Password confirmation', widget = forms.PasswordInput(), error_messages={'required': 'A confirmed password is required.'})
def clean_password2(self):
if 'password1' in self.cleaned_data:
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 == password2:
return password2
raise forms.ValidationError('Passwords must be identical. Remember, passwords are case-sensitive.')
def clean_email2(self):
if 'email1' in self.cleaned_data:
email1 = self.cleaned_data['email1']
email2 = self.cleaned_data['email2']
if email1 == email2:
if User.objects.get(email = email1):
raise forms.ValidationError("The email address '%s' is already associated with an account. This typically means you created an account in the past. Please use it." % email1)
else:
return email2
raise forms.ValidationError('Email addresses must be identical.')
def clean_username(self):
if 'username' in self.cleaned_data:
username = self.cleaned_data['username']
if not re.search(r'^\w+$', username):
raise forms.ValidationError('Username can only contain letters, numbers, and the underscore characters.')
try:
User.objects.get(username = username)
except User.DoesNotExist:
return username
raise forms.ValidationError("Username '%s' is already taken." % username)
The problem pops up in the form.is_valid() and clean_username(). If I add a user that does or does not exist (it doesn't matter if the user exists or not, behavior is the same) and populate the form with data I know is valid, the code should simply return username from clean_username() and form.is_valid() should be True. Instead, I get an error page that looks like this:
DoesNotExist at /register/
User matching query does not exist.
Request Method: POST
Request URL: http://127.0.0.1:8000/register/
Django Version: 1.4.1
Exception Type: DoesNotExist
Exception Value:
User matching query does not exist.
Exception Location: /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py in get, line 366
Python Executable: /opt/local/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
Python Version: 2.7.2
Python Path:
['/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/distribute-0.6.28-py2.7.egg',
'/Library/Python/2.7/site-packages/bpython-0.10.1-py2.7.egg',
'/Library/Python/2.7/site-packages/Pygments-1.5-py2.7.egg',
'/Library/Python/2.7/site-packages/django_registration-0.8-py2.7.egg',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PIL',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg-info',
'/Library/Python/2.7/site-packages']
Server time: Sun, 28 Oct 2012 00:51:58 -0400
It's got to be something small I'm missing, but I can't see it.
In your code
def clean_email2(self):
...
# here
if User.objects.get(email = email1):
raise forms.ValidationError("The email address '%s' is already associated with an account. This typically means you created an account in the past. Please use it." % email1)
...
The get() could cause DoesNotExist but is not captured. Is that the issue?
Also, please provide full traceback of the line making the issue.
Furthermore, according to the doc, its better to put the logic of validating passwords & emails to the clean() method.
I want to create a SINGLE form which gives the ability to the admin to create a new user with extended profile. Please note that, I don't want to use admin and registration apps.
I have extended the user with the UserProfile model. I have read all the documents related to extending user profile. But, I really don't know how to save these information.
I coded the following django form for this issue:
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField()
last_name = forms.CharField()
password1=forms.CharField(max_length=30,widget=forms.PasswordInput()) #render_value=False
password2=forms.CharField(max_length=30,widget=forms.PasswordInput())
email=forms.EmailField(required=False)
title = forms.ChoiceField(choices=TITLE_CHOICES)
def clean_username(self): # check if username dos not exist before
try:
User.objects.get(username=self.cleaned_data['username']) #get user from user model
except User.DoesNotExist :
return self.cleaned_data['username']
raise forms.ValidationError("this user exist already")
def clean(self): # check if password 1 and password2 match each other
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
raise forms.ValidationError("passwords dont match each other")
return self.cleaned_data
def save(self): # create new user
new_user=User.objects.create_user(username=self.cleaned_data['username'],
first_name=self.cleaned_data['first_name'],
last_name=self.cleaned_data['last_name'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'],
)
return new_user
Is it OK? however it gives me an error in first_name and last_name. Says django doesn't expect first_name and last_name in save() method.
create_user only supports the username, email and password arguments. First call create_user, then add the extra values to the saved object.
new_user=User.objects.create_user(self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.save()