Django custom user authentication is not working properly - django

i am using custom user authentication model which uses an email address as the username and creates the user but even if password1 is different than password2 the registration completes successfully. i am unable to debug the problem.
here is models.py file:
class UserManager(auth_models.BaseUserManager):
def create_user(self, email, first_name, last_name, password):
"""
Creates and saves a user with given email,
first name, last name and password.
"""
if not email:
raise ValueError("users must have an email address")
user = self.model(
email=UserManager.normalize_email(email),
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.save(self._db)
return user
def create_superuser(self, email, first_name, last_name, password):
"""
Creates and saves a super_user with given email,
first name, last name and password.
"""
if not email:
raise ValueError("users must have an email address")
user = self.model(
email=UserManager.normalize_email(email),
first_name=first_name,
last_name=last_name,
)
user.is_admin = True
user.set_password(password)
user.save(self._db)
return user
class User(auth_models.AbstractBaseUser):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
joined_at = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', ]
def get_full_name(self):
return self.first_name + " " + self.last_name
def get_short_name(self):
return self.first_name
def __str__(self):
return self.get_full_name() + ", email= " + self.email
#property
def is_staff(self):
return self.is_admin
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
class Meta:
verbose_name_plural = "users"
admin.py
class UserCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='password', widget=forms.PasswordInput)
password2 = forms.CharField(label='confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
def clean_password(self):
"""
check that the two password entries match
"""
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("passwords don't match")
return password2
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""
A form for updating users. includes all the fields
on the user, but replaces the password field with
the admin's password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'password', 'is_active', 'is_admin')
def clean_password(self):
"""
Regardless of what the user provides, return the initial value.
This is done here, rather than on the field, because the field
does not have access to the initial value.
"""
return self.initial["password"]
views.py
def register(request):
args = {}
args.update(csrf(request))
if request.method == 'POST':
form = UserCreationForm(request.POST)
args['form'] = form
if form.is_valid():
form.save()
return HttpResponseRedirect('/home/')
else:
args['form'] = UserCreationForm()
return render_to_response('authentication/signup.html', args, context_instance=RequestContext(request))

Try moving the password comparison logic present in the clean_password() function to a clean() function in the UserCreationForm.
The clean_fieldname() function should operate on the field fieldname and not any other field.
Also, when fields validation depends on each other then the best place to place the validation logic is inside the clean() method.
From Django docs:
We are performing validation on more than one field at a time, so the
form’s clean() method is a good spot to do this.
By the time the form’s clean() method is called, all the individual
field clean methods will have been run (the previous two sections), so
self.cleaned_data will be populated with any data that has survived so
far. So you also need to remember to allow for the fact that the
fields you are wanting to validate might not have survived the initial
individual field checks.
Code:
class UserCreationForm(forms.ModelForm):
...
def clean(self):
cleaned_data = super(UserCreationForm, self).clean()
password1 = cleaned_data.get("password1")
password2 = cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("passwords don't match")
return cleaned_data

The problem is, you doesn't has a 'password' field,
you need change the method name to, clean_password1 or clean_password2.
the method you created clean_password, will never be called
because there is no field called password
def clean_password1(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("passwords don't match"")
return password1

Related

why does clean_password2() method work but not clean_password1() in Django usercreationform

I am trying to figure out why this works if someone could maybe explain it to me.
I've just created a custom user model (shown below) and for the password validation it uses the clean_password2(self): (shown below) method however when I try to use clean_password1(self): (shown below) the validation does not work. why? Surely using either password1 or password2 to clean the data would work since they are the same?
Django docs state that we can use clean_<fieldname>(): methods to clean/validate data and since password1 is a fieldname in my mind that should work.
Custom user model
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError("Users must have an email address")
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None):
user = self.create_user(email=email, password=password)
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(verbose_name="Email Address", max_length=255, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
This works
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(
label="Password",
help_text=password_validation.password_validators_help_text_html(),
widget=forms.PasswordInput,
)
password2 = forms.CharField(
label="Confirm Password",
help_text="Enter the same password as before for validation",
widget=forms.PasswordInput,
)
class Meta:
model = User
fields = ["email"]
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
This doesn't
def clean_password1(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return password1
Summary: don't reference other fields in clean_<fieldname> methods. Do this logic in the clean method instead. https://docs.djangoproject.com/en/stable/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
The why goes deep into Django forms. The method that calls clean_<fieldname> is the following:
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
In _clean_fields, each field is resolved in the order they appear on the form, and this is the first time cleaned_data is filled in for that field. Because password1 comes before password2 in the fields list, when clean_password1 is run, cleaned_data["password2"] has not yet been set. Here is what happens to your code (I added comments):
def clean_password1(self):
password1 = self.cleaned_data.get("password1")
# `"password2"` is not present in cleaned_data, so `password2` is set to None
password2 = self.cleaned_data.get("password2")
# With `password2 == None`, this condition resolves to false
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
# `password1` is returned without any validation error
return password1
The reason clean_password2 works is because password2 comes later in the field list.

django custom user can't set attribute error

I followed CodingEntrepreneurs tutorial on Custom Users and extended it to have 3 types of users: school, parent and vendor.
I have created view, form for each type of user.
In forms.py I have
class ParentSignUpForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta():
model = User
fields = ('email', )
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
user = super(ParentSignUpForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.is_parent = True
user.save()
return user
I try to change is_parent attribute from False to True. However, error is:
File "/home/azamat/dev/dj_test/src/accounts/forms.py", line 137, in save
user.is_parent = True
AttributeError: can't set attribute
How to solve this issue? Or any better way to save users with different types?
UPDATE:
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager
)
class UserManager(BaseUserManager):
def create_user(self, email, password=None, is_staff=False, is_admin=False, is_active=True, is_parent=False, is_school=False, is_vendor=False):
if not email:
raise ValueError("Users must have an email address")
if not password:
raise ValueError("Users must have a password")
user_obj = self.model(
email = self.normalize_email(email)
)
user_obj.set_password(password) # change user password
user_obj.parent = is_parent
user_obj.school = is_school
user_obj.vendor = is_vendor
user_obj.active = is_active
user_obj.staff = is_staff
user_obj.admin = is_admin
user_obj.save(using=self._db)
return user_obj
def create_parentuser(self, email, password=None):
user = self.create_user(
email,
password=password,
is_parent=True
)
return user
def create_schooluser(self, email, password=None):
user = self.create_user(
email,
password=password,
is_school=True
)
return user
def create_vendoruser(self, email, password=None):
user = self.create_user(
email,
password=password,
is_vendor=True
)
return user
def create_staffuser(self, email, password=None):
user = self.create_user(
email,
password=password,
is_staff=True
)
return user
def create_superuser(self, email, password=None):
user = self.create_user(
email,
password=password,
is_staff=True,
is_admin=True,
)
return user
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
active = models.BooleanField(default=True) # can login
parent = models.BooleanField(default=False) # parent user
school = models.BooleanField(default=False) # school admin user
vendor = models.BooleanField(default=False) # vendor user
staff = models.BooleanField(default=False) # staff user non superuser
admin = models.BooleanField(default=False) # superuser
timestamp = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email' #username
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_parent(self):
return self.parent
#property
def is_school(self):
return self.school
#property
def is_vendor(self):
return self.is_vendor
#property
def is_active(self):
return self.active
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
How I solved it:
I have added REQUIRED_FIELDS = ['parent', 'school', 'vendor' ] to my model.py So now on my registration page, I have 3 check buttons where I can select a needed type of user.
In forms.py I left only RegisterForm and deleted register forms for my 3 user types
class RegisterForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email', **'parent', 'school', 'vendor'**) #'added 3 fields',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
# user.active = False # send confirmation email
if commit:
user.save()
return user

RegisterForm() missing 1 required positional argument: 'request'

So I'm making a custom user model. This is what I'am following Here. I have been pretty much following the tutorial but still I cant make it done.
Error: RegisterForm() missing 1 required positional argument: 'request'.
here's my code.
forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'password', 'active', 'admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class LoginForm(forms.ModelForm):
email = forms.EmailField(label='Email')
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email', 'password',)
widgets = {
'email' : forms.EmailInput(
attrs={'class':'form-control', 'place_holder': '', }),
'password' : forms.PasswordInput(
attrs={'class':'form-control' }),
}
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
models.py
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class UserManager(BaseUserManager):
def create_user(self, email, full_name, password=None, is_staff=False, is_active=True, is_admin=False):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
if not full_name:
raise ValueError('Users must have an full name')
if not password:
raise ValueError('Users must have a password')
user = self.model(
email=self.normalize_email(email),
)
user.full_name = full_name
user.set_password(password)
user.staff = is_staff
user.admin = is_admin
user.active = is_active
user.save(using=self._db)
return user
def create_staffuser(self, email, password):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email, full_name, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.model(
email=self.normalize_email(email)
)
user.full_name = full_name
user.set_password(password)
user.full_name = full_name
user.staff = True
user.admin = True
user.save(using=self._db)
return user
# Create your models here.
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, null=True, blank=True)
active = models.BooleanField(default=True) # to login
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
created_date = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['full_name'] # Email & Password are required by default.
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"Is the user a member of staff?"
return self.staff
#property
def is_admin(self):
"Is the user a admin member?"
return self.admin
#property
def is_active(self):
"Is the user active?"
return self.active
class Account_type(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
account_type = models.ForeignKey(Account_type, on_delete=models.CASCADE)
register.html
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def RegisterForm(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
The view logic is simple as you can see. Just saving up the request into the database. The tutorial itself did not tell anything about the view for login and register.
So, What am I doing wrong here.
Thank you
The problem is that your view RegisterForm has the same name as your form, hence if you call RegisterForm in your view, it will resolve to the view function, and make a recursive call.
Normally (top-level) functions are written in snake_case, hence you can rewrite it to register_form, or even better register (since it is not a form at all):
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('some-view-name')
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
Normally a successful POST request results in a redirect to implement the Post/Redirect/Get pattern [wiki]. So I strongly advise you to use redirect(..) [Django-doc] and replace some-view-name with the name of a view to which you want to redirect.

Django form creates default User rather than acustom User. How do I create a Custom User?

Trying to extend Django's basic user model to a custom user model. I have a form for users to register, but when the form is sent it creates a default user, not a custom user.
I want it to create a custom user. The only way I seem to be able to create a custom user currently is through admin.
Here is my Django custom user model, which exists and can add users via admin.
class MyUserManager(BaseUserManager):
def create_user(first_name, last_name, zipcode, email, username, password):
if not first_name:
raise ValueError("Users must have a first name.")
if not last_name:
raise ValueError("Users must have a last name.")
if not zipcode:
raise ValueError("Users must have a zipcode.")
if not email:
raise ValueError("Users must have an email.")
if not username:
raise ValueError("Users must have a username.")
if not password:
raise ValueError("Users mush have a password.")
user=self.model(
first_name = first_name,
last_name = last_name,
zipcode = zipcode,
email=email,
is_logged_in=is_logged_in,
is_bot=is_bot
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
class CustomUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=25,
validators = [
RegexValidator(regex = USERNAME_REGEX,
message='Firstname must be alphanumeric or contain numbers',
code='invalid_firstname'
)]
)
last_name = models.CharField(max_length=25,
validators = [
RegexValidator(regex = USERNAME_REGEX,
message='Lastname must be alphanumeric or contain numbers',
code='invalid_lastname'
)]
)
zipcode = models.CharField(
max_length=10,
null=True,
blank=True,
help_text="zipcode",
validators=[RegexValidator(
regex=r'^(^[0-9]{5}(?:-[0-9]{4})?$|^$)',
message=(u'Must be valid zipcode in formats 12345 or 12345-1234'),
)],
)
email = models.EmailField(max_length = 250,
unique=True,
verbose_name = 'email_address')
username = models.CharField(max_length = 25,
validators = [
RegexValidator(regex = USERNAME_REGEX,
message='Username must be alphanumeric or contain numbers',
code='invalid_username'
)],
unique=True
)
password = models.CharField(max_length =25,
null=True)
objects=MyUserManager()
def get_short_name(self):
# The user is identified by their email address
return self.email
def has_perm(self, perm, obj=None):
#"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
#"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
def __str__(self):
return f'{self.first_name} ({self.last_name}) ({self.email})'
Here is my views file where I'm saving the form.
#views.py
def registration(request):
if request.method == "POST":
form = CustomUserCreationForm(request.POST, instance=request.user)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
messages.success(request, f'Your account has been created! Please proceed to agreements and payment.')
return redirect('agreements_page')
else:
form = CustomUserCreationForm()
return render(request, 'registration.html', {'form': form})
here is my form.py file
class CustomUserCreationForm(forms.ModelForm):
username = forms.CharField(label='Username', widget=forms.TextInput(attrs={'class': "form-control"}))
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class': "form-control"}))
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput(attrs={'class': "form-control"}))
first_name = forms.CharField(label='First Name', widget=forms.TextInput(attrs={'class': "form-control"}))
last_name = forms.CharField(label='Last Name', widget=forms.TextInput(attrs={'class': "form-control"}))
zipcode = forms.CharField(label='Zipcode', widget=forms.NumberInput(attrs={'class': "form-control"}))
email = forms.CharField(label= 'Email', widget=forms.EmailInput(attrs={'class': "form-control"}))
class Meta:
model = CustomUser
fields = ['first_name', 'last_name', 'email', 'zipcode', 'username']
def clean_password(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords do not match")
return password2
def save(self, commit=True):
user = super(CustomUserCreationForm, self).save(commit=False)
user.username = self.cleaned_data['username']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.zipcode = self.cleaned_data['zipcode']
user.email = self.cleaned_data['email']
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
You need to tell your app that your default user model is CustomUser. To do that, you need to add this to your settings.py:
AUTH_USER_MODEL = 'your_app_name.CustomUser'
And in your view, you need to access your user such as:
profile.user = request.user.get_profile()
This is also specified in a complete custom user example in the official site:
Finally, specify the custom model as the default user model for your project using the AUTH_USER_MODEL setting in your settings.py.

self.cleaned_data.get returns none even if field was declared

When i'm in the admin page and trying to create a new instance of MyUser I am unable to create it. When I print out password and confirm_password, I get the proper value for password but None for confirm_password.
In my admins.py file, I have the following:
class MyUserCreationForm(forms.ModelForm):
"""
A form for creating new users.
"""
password = forms.CharField(label='Password', widget=forms.PasswordInput)
confirm_password = forms.CharField(
label='Confirm password', widget=forms.PasswordInput)
class Meta:
models = MyUser
fields = ('email', )
def clean_password(self):
"""
Check if two password entries match.
"""
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if (password == confirm_password):
return password
else:
raise forms.ValidationError("Passwords don't match")
def save(self):
"""
Save the provided password in hash format.
"""
user = super().save(commit=False)
user.set_password(self.cleaned_data['password'])
user.save()
return user
What could be causing as to why confirm_password always have the value None?
You should not do this code in the clean_password.
It makes more sense to do it inside clean_confirm_password
Here is a snipet retrieve from django source code:
def clean_confirm_password(self):
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("confirm_password")
if password and confirm_password and password != confirm_password:
#you can keep your simply Validation Error here
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
And for the save try:
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
Otherwise your code seems to be good.
So maybe the error is somewhere else.
Here for your information: https://github.com/django/django/blob/master/django/contrib/auth/forms.py#L70