I am making a form in Django and I am using the "form.is_valid" to get all the error. Everything works except the minimum value for the password. I have following code for my form:
class RegisterationForm (forms.Form):
first_name = forms.CharField(initial ='' ,widget=forms.TextInput(attrs={'class' : 'form-control'}),max_length = 20)
last_name = forms.CharField(initial ='' ,widget=forms.TextInput(attrs={'class' : 'form-control'}),max_length = 20)
username = forms.CharField(initial ='' ,widget=forms.TextInput(attrs={'class' : 'form-control'}),min_length = 5,max_length = 20)
email = forms.EmailField(initial ='' ,widget=forms.TextInput(attrs={'class' : 'form-control'}))
password = forms.CharField(widget=forms.TextInput(attrs={'class' : 'form-control'}))
password2 = forms.CharField(widget=forms.TextInput(attrs={'class' : 'form-control'}))
def clean(self):
cleaned_data = super(RegisterationForm, self).clean()
password = self.cleaned_data['password']
password2 = self.cleaned_data['password2']
if password and password != password2:
raise forms.ValidationError("passwords do not match")
return self.cleaned_data
def clean_username(self):
username = self.cleaned_data['username']
return username
def clean_email(self):
email = self.cleaned_data['email']
return email
def clean_password(self):
password= self.cleaned_data['password']
if len(password) < 6:
raise forms.ValidationError("Your password should be at least 6 Characters")
return password
but here when I enter a password less than 6 characters, instead of getting a validation error I get an error from Django. The error is a key error which is caused because the cleaned_data dictionary does not contain the password when it's longer than 6 chars. I also used the min_length feature in form definition as well and the same thing happened.
If password or password2 is not valid, then they will not be in cleaned_data. You need to change your clean method to handle this. For example:
def clean(self):
cleaned_data = super(RegisterationForm, self).clean()
password = self.cleaned_data.get('password')
password2 = self.cleaned_data.get('password2')
if password and password2 and password != password2:
raise forms.ValidationError("passwords do not match")
You could specify min_length in your password field. Then Django will validate the length for you, and you can remove your custom clean method.
password = forms.CharField(min_length=6, widget=forms.TextInput(attrs={'class' : 'form-control'}))
Finally, your clean_username and clean_email methods are not doing anything so you can simplify your form by removing them.
Related
I am trying to create a new user for my application by following this tutorial . I am able to create a new user but the on opening django admin page the password is shown as
"Invalid password format or unknown hashing algorithm."
I have seen similar questions where the answer was to set
account.set_password(password)
I have tried this but it did not work for me.
(EDIT: It seems the .save() is not being called from views.py. I am not sure why)
Here is my code
Serializer.py
class RegistraionSerialzer(serializers.ModelSerializer):
password2 = serializers.CharField(style={'input_type':'password'},read_only=True)
class Meta:
model = User
fields = ('phone','name','password','password2','user_type','email')
extra_kwargs = {
'password': {'write_only' : True},
}
def save(self):
print('here')
account = User(
phone = self.validated_data['phone'],
email = self.validated_data['email']
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
print(password)
return serializers.ValidationError({'password':'password mismatch'})
print(password)
account.set_password(password)
account.save()
Views.py
#api_view(['POST'])
def Registraion(request):
serializer = RegistraionSerialzer(data=request.data)
data = {}
print('reg vie')
if serializer.is_valid():
account = serializer.save()
data['response'] = "Successfully registered "
data['name'] = account.name
data['password'] = account.password
print(data)
else:
print(serializer.errors)
return Response(data)
try this
from django.contrib.auth.hashers import make_password
class RegistraionSerialzer(serializers.ModelSerializer):
password2 = serializers.CharField(style={'input_type':'password'},read_only=True)
class Meta:
model = User
fields = ('phone','name','password','password2','user_type','email')
extra_kwargs = {
'password': {'write_only' : True},
}
def save(self):
print('here')
account = User(
phone = self.validated_data['phone'],
email = self.validated_data['email']
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
print(password)
return serializers.ValidationError({'password':'password mismatch'})
print(password)
account.set_password(make_password(password))
account.save()
I'm doing a little password confirmation form in django. But Im confused as the self.cleaned_data.get('confirm_password') always returns none and hence my passwords never match to one another.
Heres the clean method in the forms.py
def clean_password(self):
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("confirm_password")
if password != confirm_password:
print(password)
print(confirm_password)
raise forms.ValidationError(
"Password and password confirmation does not match"
)
return password
self.cleaned_data.get('password') returns the typed password but the confirm_password doesnt.
In the view.py when I see the received data before cleaning, the confirm_password shows as it is
......................user = UserRegister(request.POST)
print(request.POST.get('confirm_password'))
if user.is_valid():
print('valid')..........................
What could possibly be the reason for this??
Heres the form declaration part in forms.py
first_name = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'First Name'}))
last_name = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'Last Name'}))
username = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'Username'}))
email = forms.EmailField( required=True, widget=forms.widgets.EmailInput(attrs={'placeholder': 'Email'}))
password =forms.CharField(required=True, widget=forms.widgets.PasswordInput())
confirm_password =forms.CharField(required=True, widget=forms.widgets.PasswordInput())
class Meta:
model=User
fields=['first_name','last_name','username','email','password','confirm_password']
clean_fieldname methods called in order of fields declaration, so at the moment clean_password is called cleaned_data does not contain confirm_password. You can perform this validation in clean_confirm_password method:
def clean_confirm_password(self):
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("confirm_password")
if password != confirm_password:
print(password)
print(confirm_password)
raise forms.ValidationError(
"Password and password confirmation does not match"
)
return password
or just use clean method for validation that requires access to multiple form fields.
The clean_<fieldname>() methods are called as the fields are being validated. You can't count on any other fields being in cleaned_data at that time except for the field you are working with. If you need to work with multiple fields override the form's clean() method.
Since you do the validation between multiple fields you should override form's cleanmethod.
def clean(self):
cleaned_data = super().clean()
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("confirm_password")
if password != confirm_password:
print(password)
print(confirm_password)
raise forms.ValidationError(
"Password and password confirmation does not match"
)
return cleaned_data
I'm having a little trouble validating two fields (password and password confirmation) in the same form.
The thing is that after validating password with a method I've created, when I try to validate password confirmation, I no longer have access to this variable, and password = self.cleaned_data['password'] is 'None'.
class NewAccountForm(forms.Form):
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'narrow-input', 'required': 'true' }), required=True, help_text='Password must be 8 characters minimum length (with at least 1 lower case, 1 upper case and 1 number).')
password_confirm = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'narrow-input', 'required': 'true' }), required=True, )
def __init__(self, *args, **kwargs):
super(NewAccountForm, self).__init__(*args, **kwargs)
self.fields['password'].label = "Password"
self.fields['password_confirm'].label = "Password Confirmation"
"Password validation" <- this validation is working.
def clean_password(self):
validate_password_strength(self.cleaned_data['password'])
This second validation isn't correctly performed because password = 'None':
def clean_password_confirm(self):
password = self.cleaned_data['password']
password_confirm = self.cleaned_data.get('password_confirm')
print(password)
print(password_confirm)
if password and password_confirm:
if password != password_confirm:
raise forms.ValidationError("The two password fields must match.")
return password_confirm
Is there a way to use input for field password as a variable to the second validation (clean_password_confirm) if it is already validated by the first method (clean_password)?
Thanks.
EDIT: Updated version:
def clean(self):
cleaned_data = super(NewAccountForm, self).clean()
password = cleaned_data.get('password')
# check for min length
min_length = 8
if len(password) < min_length:
msg = 'Password must be at least %s characters long.' %(str(min_length))
self.add_error('password', msg)
# check for digit
if sum(c.isdigit() for c in password) < 1:
msg = 'Password must contain at least 1 number.'
self.add_error('password', msg)
# check for uppercase letter
if not any(c.isupper() for c in password):
msg = 'Password must contain at least 1 uppercase letter.'
self.add_error('password', msg)
# check for lowercase letter
if not any(c.islower() for c in password):
msg = 'Password must contain at least 1 lowercase letter.'
self.add_error('password', msg)
password_confirm = cleaned_data.get('password_confirm')
if password and password_confirm:
if password != password_confirm:
msg = "The two password fields must match."
self.add_error('password_confirm', msg)
return cleaned_data
You can test for multiple fields in the clean() method.
Example:
def clean(self):
cleaned_data = super(NewAccountForm, self).clean()
password = cleaned_data.get('password')
password_confirm = cleaned_data.get('password_confirm ')
if password and password_confirm:
if password != password_confirm:
raise forms.ValidationError("The two password fields must match.")
return cleaned_data
See the documentation on Cleaning and validating fields that depend on each other.
I am working on a Django project and it seems like I can not use the cleaned_data module anywhere in my program. Every time I use it, it raises a key error (saying that key doesn't exist) and when I use cleaned_data.get it just passes nothing. I can use only "form.data" (as you can see in my code) and everything works fine. I just want to know why I can't use the cleaned_data?
here is my form.py:
class RegisterationForm(forms.Form):
first_name = forms.CharField
last_name = forms.CharField
username = forms.CharField
email = forms.EmailField
password = forms.CharField
password2 = forms.CharField
def clean(self):
password = self.cleaned_data.get('password')
password2 = self.cleaned_data.get('password2')
if password and password != password2:
raise forms.ValidationError("passwords do not match")
return self.cleaned_data
here is my view.py:
def register(request):
if request.method == 'POST':
form = RegisterationForm(request.POST)
if form.is_valid():
user_info={}
user_info['username'] = form.data['username']
user_info['first_name'] = form.data['first_name']
user_info['last_name'] = form.data['last_name']
user_info['password'] = form.data['password']
user_info['email']= form.data['email']
#salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
#usernamesalt = user_info['username']
#if isinstance(usernamesalt, unicode):
# usernamesalt = usernamesalt.encode('utf8')
user_info['activation_key'] = 1#hashlib.sha1(salt+usernamesalt).hexdigest()
form.sendEmail(user_info)
form.save(user_info)
return render_to_response('register_success.html',user_info)
else:
form_save = form
args = {}
args.update(csrf(request))
args['form'] = RegisterationForm()
return render_to_response('register.html',args)
Because you didn't call the parent class clean method to get the data first:
def clean(self):
cleaned_data = super(RegisterationForm, self).clean()
password = cleaned_data.get('password')
password2 = cleaned_data.get('password2')
if password and password != password2:
raise forms.ValidationError("passwords do not match")
Check out django doc about clean method.
If that's really your actual code, your form doesn't have any fields because you have not called any of the field definitions. It should be:
class RegisterationForm(forms.Form):
first_name = forms.CharField()
last_name = forms.CharField()
username = forms.CharField()
email = forms.EmailField()
password = forms.CharField()
password2 = forms.CharField()
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