Reputation: 665
I want to replace username with email in django authentication.So when I was going through documentation it says that
If you’re starting a new project, it’s highly recommended to set up a custom user model, even if the default User model is sufficient for you
So First I created a custom user model which extends AbstractUser.In which I made username=None and USERNAME_FIELD='email'
class User(AbstractUser):
username = None
first_name = None
last_name = None
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
Then I created a modelform which uses custom user model.When I render this form in my template, password and confirm password field is missing.I don't know whats going wrong.
class UserForm(forms.ModelForm):
class Meta:
model = get_user_model()
fields = ['email']
I thought password and confirm password will be there by default.Am I right?
Upvotes: 0
Views: 1797
Reputation: 477533
I thought password and confirm password will be there by default.Am I right?
No. A ModelForm
has logic to construct a Form
based on the model you provide. But it does not treat a user model differently than another model. If you specify fields = ['email']
, it will simply create a form with the email
field, as the only one.
To make matters even worse, it will not create a correct user object, since the passwords should be hashed, you can store the hashed password with the .set_password(…)
method [Django-doc]. We thus can create a form that looks like:
class UserCreateForm(forms.ModelForm):
password = forms.CharField(
label='Password',
strip=False,
widget=forms.PasswordInput()
)
def save(self, *args, **kwargs):
self.instance.set_password(self.cleaned_data['password'])
return super().save(*args, **kwargs)
class Meta:
model = get_user_model()
fields = ['email']
If you want to validate the passwords, you need to add some extra logic:
from django.core.exceptions import ValidationError
class UserCreateForm(forms.ModelForm):
password = forms.CharField(
label='Password',
strip=False,
widget=forms.PasswordInput()
)
password2 = forms.CharField(
label='Repeat password',
strip=False,
widget=forms.PasswordInput()
)
def clean(self, *args, **kwargs):
cleaned_data = super().clean(*args, **kwargs)
if cleaned_data['password'] != cleaned_data['password2']:
raise ValidationError('Passwords do not match')
return cleaned_data
def save(self, *args, **kwargs):
self.instance.set_password(self.cleaned_data['password'])
return super().save(*args, **kwargs)
class Meta:
model = get_user_model()
fields = ['email']
Upvotes: 0
Reputation: 10237
You need to specify all the fields you want to be in the form:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
password_confirm = forms.CharField(widget=forms.PasswordInput())
class Meta:
fields = ['email', 'password']
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get("password")
password_confirm = cleaned_data.get("password_confirm")
if password != password_confirm:
self.add_error('password_confirm', "Password does not match")
return cleaned_data
Note however that you need to manually validate that password_confirm
field matches password
field
Upvotes: 1