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
Related
I am trying to setup user authentication for the login page using forms and comparing it to my database value but it does not work. I also tried using this particular questions User Login Authentication using forms and Django logic to solve my problem but it didn't help.
Models.py
from django.db import models
from django.contrib.auth.password_validation import validate_password
class student(models.Model):
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150)
matric_number = models.CharField(max_length=9)
email = models.EmailField(max_length=50)
password1 = models.CharField(max_length=255, validators=[validate_password])
password2 = models.CharField(max_length=255)
def __str__(self):
return (self.matric_number)
This view saves user info to database
def student(request):
if request.method == 'POST':
form = studentForm(request.POST)
if form.is_valid():
sign_up = form.save(commit=False)
#sign_up.password1 = make_password(form.cleaned_data['password1'])
#sign_up.password2 = make_password(form.cleaned_data['password2'])
sign_up.status = 1
sign_up.save()
user = form.cleaned_data.get('matric_number')
messages.success(request, "Account was created for "+str(user))
return redirect(signin)
else:
form = studentForm()
return render(request, 'Student.html',{
"form": form
})
This is the signin view
def signin(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
try:
student = student.object.get(username=username, password=password)
return redirect(files)
except:
messages.success(request, "Error")
else:
form = LoginForm()
return render(request, "SignIn.html",{
"form":form
})
This is my form.py
class studentForm(forms.ModelForm):
class Meta:
model=student
fields="__all__"
widgets={
'first_name':forms.TextInput(attrs={'placeholder': 'Enter Your First Name'}),
'last_name':forms.TextInput(attrs={'placeholder': 'Enter Your Last Name'}),
'matric_number':forms.TextInput(attrs={'placeholder': 'Enter Your Matric Number'}),
'email':forms.EmailInput(attrs={'placeholder': 'abc#example.com'}),
'password1':forms.PasswordInput(attrs={'placeholder': 'Enter Your Preferred Password','id':'password'}),
'password2':forms.PasswordInput(attrs={'placeholder':'Confirm Your Password', 'id':'password1'})
}
def clean(self):
super(studentForm, self).clean()
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
matric_number = self.cleaned_data.get('matric_number')
email = self.cleaned_data.get('email')
try:
if password1 != password2:
self.errors[''] = self.error_class(["The two password fields must match"])
elif len(matric_number) != 9:
self.errors[''] = self.error_class(["You have entered an invalid matric number"])
elif len(matric_number) == 9:
matric_number = int(matric_number)
except ValueError:
self.errors[''] = self.error_class(["You have entered an invalid matric number"])
for instance in student.objects.all():
if instance.matric_number == str(matric_number):
self.errors[''] = self.error_class(["Matric number already exist"])
elif instance.email == email:
self.errors[''] = self.error_class(["E-mail address already exist"])
class LoginForm(forms.Form):
matric_number = forms.CharField(max_length=9, widget=forms.TextInput(attrs={'id': 'username', 'placeholder': 'Enter Your Staff Id Or Matric Number'}))
password1 = forms.CharField(max_length=9, widget=forms.PasswordInput(attrs={'id': 'password', 'placeholder':'Enter Your password'}))
Stop reinventing the wheel. Also, class names are supposed to be named with PascalCase.
Use AbstractUser model:
from django.contrib.auth.models import AbstractUser
class Student(AbstractUser):
...
and in your main urls.py:
from django.contrib.auth import views as auth_views
urlpatterns = [
...
path('login/', auth_views.LoginView.as_view(), name='login'),
...
]
It is much faster and SAFER way to create new user.
So I figured out out how to solve my problem. By using the AbstractUser model,i was able to create a custom user and then create another model which i extended a ForeignKey on the User model therefore allowing me to tie every user to their profile.
Here is my models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
pass
def __str__(self):
return self.username
class UserProfile(models.Model):
"""
This is the one for model.py
"""
username = models.ForeignKey(User, on_delete=models.CASCADE, null=True, default="")
profile_picture = models.ImageField(blank=True, null=True, default="")
matricno = models.CharField(max_length=9, default="", primary_key=True)
email = models.EmailField(default="")
first_name = models.CharField(max_length=200, default="")
last_name = models.CharField(max_length=255, default="")
class Meta:
verbose_name_plural = "Users Profile"
def __str__(self):
return self.first_name+ " "+self.last_name
And here is my views.py
def signup(request):
if request.method == "POST":
form = Signup(request.POST)
if form.is_valid():
username = request.POST["username"]
email = request.POST["email"]
password = request.POST["password"]
password2 = request.POST["password2"]
user = User.objects.create_user(
username=username,
password=password,
email=email,
)
user.save()
login(request, user)
messages.success(request, "Account Created successfully for " + username)
return redirect(details)
else:
form = Signup()
return render(request, "accounts/register.html", {"form": form})
def details(request, username):
user = User.objects.get(username=username)
form = Details()
if request.method == "POST":
form = Details(request.POST, request.FILES)
if form.is_valid():
detail = form.save(commit=False)
detail.username = request.user
detail.save()
return redirect(success, pk=detail.pk)
else:
form = Details(initial={"matricno":request.user.username})
return render(request, "details.html", {"form":form})
And finally my forms.py that i use in creating a signup form and perfoming validation
class Signup(forms.Form):
username = forms.CharField(
max_length=9,
widget=forms.TextInput(attrs={"placeholder": "Enter Your Matric Number"}),
)
email = forms.EmailField(
max_length=255,
widget=forms.EmailInput(attrs={"placeholder": "Enter Your E-mail Address"}),
)
password = forms.CharField(
max_length=255,
widget=forms.PasswordInput(
attrs={"placeholder": "Enter Your Password", "id": "password"}
),
)
password2 = forms.CharField(
max_length=255,
widget=forms.PasswordInput(
attrs={"placeholder": "Confirm Your Password", "id": "password2"}
),
)
def clean(self):
super(Signup, self).clean()
password = self.cleaned_data.get("password")
password2 = self.cleaned_data.get("password2")
username = self.cleaned_data.get("username")
email = self.cleaned_data.get("email")
if password != password2:
self.errors[""] = self.error_class(["The two password fields must match"])
for instance in User.objects.all():
if instance.username == str(username):
self.errors[""] = self.error_class(["User already exist"])
elif instance.email == email:
self.errors[""] = self.error_class(["E-mail already in use"])
else:
pass
return self.cleaned_data
I am following a tutorial for Login in Django and after finishing I found that the Login Form requires the Username and Password but I want to replace the username with the user's Email instead.
Here is the views.py
#login_required
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
#login_required
def profile(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST,
request.FILES,
instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'users/profile.html', context)
Here is the forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
Here is the template
<form class="login100-form validate-form" method="POST">
<span class="login100-form-title p-b-34">
Account Login
</span>
<fieldset class="input100 m-b-20">
{% csrf_token %}
{{ form|crispy }}
</fieldset>
<div class="container-login100-form-btn">
<button class="login100-form-btn" type="submit" style="width: 90%">
Sign in
</button>
</div>
<div class="w-full text-center p-t-27 p-b-100">
<a class="txt2" href="{% url 'password_reset' %}">Forgot Password ?</a>
</div>
</form>
My question how to change from username to user's email?
To create a Django login with email We have to overwrite Default User, We can start writing models, but first you might want to create different app for your users (its a good practice).
Models.py
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
# notice the absence of a "Password field", that is built in.
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [] # Email & Password are required by default.
def get_full_name(self):
# The user is identified by their email address
return self.email
Django has built-in methods for the User Manager. We have to customize them in order to make our custom user model work correctly.
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
"""
Creates and saves a User with the given email and password.
"""
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
Then you need to run migrations.
python manage.py makemigrations
python manage.py migrate
Here's the post you can follow: here
go to your models.py, and add
USERNAME_FIELD = 'email'
remove username from form.
I'd recommend using django-allauth. It's a powerful tool for authenticating users and you can set the user to log-in with email instead of username by adding this to your settings.py:
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_AUTHENTICATION_METHOD='email'
You can do that in two ways. By using AbstractUser or AbstractBaseUser
AbstractUser: define your user class by subclassing AbstractUser . AbstractUser class has all the necessary fields that you might need in user(you can add more). You can do something like setting email as username field and making username field as null. Use this option if you are good with the existing fields on the User model and just want to remove the username field.
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
AbstractBaseUser:define your user class by subclassing AbstractBaseUser.It doesnt have existing fields.Use this option if you want to start from scratch by creating your own, completely new User model.
class User(AbstractBaseUser):
email = models.EmailField(('email address'), unique=True)
active = models.BooleanField(default=True) # can login
staff = models.BooleanField(default=False) # staff user non super
admin = models.BooleanField(default=False) # superuser
first_name = models.CharField(max_length=30, blank=True, null= True)
last_name = models.CharField(max_length=30, blank=True, null= True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
You need to write your custom manager depending on your need.
You can create backends.py
def authenticate(username=None, password=None):
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'username': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
# print(user.username)
return user
except User.DoesNotExist:
return None
class EmailOrUsernameModelBackend(object):
def authenticate(self, username=None, password=None):
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'username': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
# print(user.username)
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
After that, add the following code in settings.py
AUTHENTICATION_BACKENDS = (
'users.backends.EmailOrUsernameModelBackend',
'django.contrib.auth.backends.ModelBackend',
)
Then modify views.py
from django.contrib.auth import login as auth_login
def ajax_login(request):
if request.method == 'POST':
username = request.POST.get('email', '').strip()
password = request.POST.get('password', '').strip()
if username and password:
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
auth_login(request, user, backend='users.backends.EmailOrUsernameModelBackend')
try:
order = Order.objects.filter(user=request.user)
except Order.DoesNotExist:
order = None
if order is not None:
exist_order = True
else:
exist_order = False
data = {'success': True, 'order': exist_order}
else:
data = {'success': False, 'message': 'User is not active'}
else:
data = {'success': False, 'message': 'Invalid username or password'}
return JsonResponse(data)
Basically what I have done so far is create a registration page where the user makes their username and password, then that password is stored in as a hashed password (md5 hasher). The problem I am having is logging in. The user inputs their username and password then the password is authenticated by using authenticate() method in django. The problem is that authenticate() is returning None instead of matching the user and password in the database. I dont know if this affects anything but I am using PostgreSQL.
models.py
class MyAccountManager(BaseUserManager):
def create_user(self, email,username,first_name,password= None):
if not email:
raise ValueError('User must have an email address')
if not username:
raise ValueError('User must have a username')
if not first_name:
raise ValueError('User must have a first name')
user= self.model(
email=self.normalize_email(email),
username= username,
first_name= first_name
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, password):
user= self.create_user(
email= self.normalize_email(email),
username=username,
first_name= first_name,
password= password,
)
user.is_admin= True
user.is_staff= True
user.is_superuser= True
user.save(using=self._db)
return user
class User(AbstractBaseUser, models.Model):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='date joined')
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
USERNAME_FIELD= 'username'
REQUIRED_FIELDS= ['email','first_name']
objects= MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
forms.py
class LoginForm(forms.Form):
username = forms.CharField(initial='' ,label='Username:',max_length=30)
password = forms.CharField(max_length=20, widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'password')
def clean(self):
cleaned_data = super(LoginForm, self).clean()
confirm_password = cleaned_data.get('password')
class SignUpForm(forms.ModelForm):
first_name = forms.CharField(required= True,initial='',max_length=20)
last_name = forms.CharField(required=True,max_length=30, initial='')
username = forms.CharField(max_length=30,initial='', required=True)
password = forms.CharField(max_length= 20, initial='', widget = forms.PasswordInput())
password2= forms.CharField(max_length=20, initial='',widget = forms.PasswordInput())
email = forms.EmailField(max_length=60, initial='',)
class Meta:
model = User
fields = ('first_name', 'last_name','username','password2','email')
def clean(self):
cleaned_data = super(SignUpForm,self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('password2')
if(password != confirm_password):
raise forms.ValidationError(
'Password and Confirm Password do not match.'
)
views.py
def signin_and_signup(request):
if request.method == 'POST':
logout(request)
sign_in = LoginForm(request.POST)
signup = SignUpForm(request.POST)
if 'sign-in-name' in request.POST:
if sign_in.is_valid():
username = request.POST.get('username')
password= request.POST.get('password')
user = authenticate(username= username, password= password)
if user:
return HttpResponse('success')
else:
return HttpResponse('fail')
elif 'sign-up-input-name' in request.POST:
if(signup.is_valid()):
user = signup.save(commit=False)
nonHashed = signup.cleaned_data['password']
varhash = make_password(nonHashed, None, 'md5')
user.set_password(varhash)
user.save()
else:
print("Ran3<------------")
signup = SignUpForm()
else:
sign_in = LoginForm()
signup = SignUpForm()
context = {'signin':sign_in, 'signup':signup}
return render(request, 'home.html', context)
Why are you substituting the user model that django provides if you have the same attributes?
This is done in case you want to extend or add new properties to the user, for example, license number, avatar, position.
Anyway, your authenticate() maybe doesn't work because you haven't registered your new model in settings.py.
AUTH_USER_MODEL = 'name_of_the_app.User'
I recommend that you take a look at the official documentation
https://docs.djangoproject.com/en/3.1/topics/auth/customizing/
Antoher thing it could be your authentication backend:
Try:
settings.py
AUTHENTICATION_BACKENDS = [
'name_of_the_app.admin.LoginBackend',
]
Where you want for example admin.py
from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
class LoginBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try: # to allow authentication through phone number or any other field, modify the below statement
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
except MultipleObjectsReturned:
return models.User.objects.filter(email=username).order_by('id').first()
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
As you can see, you can also login with the email
Model.py
class UserProfileInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,default='')
# user = models.OneToOneField(User, on_delete=models.CASCADE)
phone_no = models.CharField(max_length=13,unique=True)
registered = models.BooleanField(default=False)
spam = models.BooleanField(default=False)
def __str__(self):
return self.user.username
Serializer.py
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField()
class Meta():
model = User
fields = ('username','email','password')
class UserProfileSerializer(serializers.ModelSerializer):
class Meta():
model = UserProfileInfo
fields = ('phone_no',)
views.py
def register(request):
registered = False
if request.method == 'POST':
user_serializer = UserSerializer(data=request.POST)
profile_serializer = UserProfileSerializer(data=request.POST)
if user_serializer.is_valid() and profile_serializer.is_valid():
user = user_serializer.save()
user.set_password(user.password) #saving hash value of password
user.save()
profile = profile_serializer.save(commit=False)
profile.user = user
profile.registered = True
profile.save()
registered = True
else:
print(user_serializer.errors)
else:
user_serializer = UserSerializer
profile_serializer = UserProfileSerializer
return Response(request,'basic_app/registration.html',{
'user_serializer':user_serializer,
'profile_form':profile_form,
'registered':registered
})
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
print(username,password)
user = authenticate(username=username, password=password)
print(user)
if user:
if user.is_active:
login(request,user)
return render(request,'basic_app/search.html')
else:
return HttpResponse('Account not active!')
else:
# print(username,password)
return HttpResponse('Login credentials not correct!')
else:
return render(request,'basic_app/login.html')
Now I need to make changes to my views.py such that I can parallely populate the user and the profile model having one to one field. I was using the form which was working well but now I need to convert the code to rest API. Please help how I can keep the same functionality using the above serializer class. My aim is to register and login the user.
First, c method in the serializer like my simple code:
(I used to write this class in my REST project for register student)
class StudentRegistrationSerializer(serializers.ModelSerializer):
password = serializers.CharField(style={'input_type': 'password'}, required=True)
password2 = serializers.CharField(style={'input_type': 'password'}, required=True)
class Meta:
model = Student
fields = ['phone_number', 'password', 'password2', 'name', 'family']
extra_kwargs = {
'password': {'write_only': True}
}
def save(self, **kwargs):
phone_number = self.validated_data.get('phone_number')
name = self.validated_data.get('name')
family = self.validated_data.get('family')
password = self.validated_data.get('password')
password2 = self.validated_data.get('password2')
not_active = User.objects.filter(username=phone_number, is_active=False)
is_active = User.objects.filter(username=phone_number, is_active=True)
if password != password2:
raise serializers.ValidationError({'error': 'password not matched'})
if is_active:
raise serializers.ValidationError({'error': 'username already exist'})
if not_active:
raise serializers.ValidationError({'error': 'username already exist active your account'})
user = User(username=phone_number, password=password, is_active=False)
user.set_password(password)
user.save()
student = Student(phone_number=phone_number, user=user, name=name, family=family)
student.save()
return student
and return the saved object here is student
and I recommend you to use build-in LoginView in the third-party library like "rest_auth" this library handles Token
after installing "rest_auth" using :
pip install django-rest-auth
in the url file just import :
from rest_auth.views import LoginView
and use it without any complexity
here is the trouble i try to autheticate the users for my website but authenticate() return alway the None value for the user created with the registration page. I can correctly log user after their user user creation and the entry is in the database. I have a custom user model extended form AbstractBaseUser. So here is the portion of code not working :
from django.contrib.auth import login as authlog
def login(request):
error = False
if request.method == "POST":
form = forms.LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
user = authenticate(username=username, password=password)
print("Validated form.")
print(username)
print(password)
print(user)
if user:
print("Logged user.")
authlog(request, user)
return redirect(to='home')
else:
print("Not logged user.")
error = True
else:
form = forms.LoginForm()
return render(request, 'users/login.html', locals())
And in the following block of code the user is sccessfully logged after it's registration.
from django.contrib.auth import login as authlog
def register(request):
form = forms.RegisterForm(request.POST or None)
if form.is_valid():
user = form.save()
authlog(request, user)
return redirect(to='home')
print('Registered new user')
return render(request, 'users/register.html', locals())
What i don't understant is why it the admin account i created with ./manage.py createsuperuser work and not the others.
And also i can't create user in the admin panel and i don't know why.
Thanks :D
EDIT: My forms
class CreateUserForm(forms.ModelForm):
pass1 = forms.CharField(label="Password", widget=forms.PasswordInput)
pass2 = forms.CharField(label="Password Check", widget=forms.PasswordInput)
class Meta:
model = models.User
fields = '__all__'
def clean_pass2(self):
pass1 = self.cleaned_data.get('pass1')
pass2 = self.cleaned_data.get('pass2')
if pass1 and pass2 and pass1 != pass2:
raise forms.ValidationError("Passwords don't match")
return pass2
def save(self, commit=True):
user = super(UserCreationForm, self)
if user.exte:
user.promo = None
user.login = None
user.save(commit=False)
user.set_password(self.cleaned_data["pass1"])
if commit:
user.save()
return user
class RegisterForm(CreateUserForm):
class Meta:
model = models.User
fields = ('email', 'lname', 'fname', 'exte', 'promo', 'login')
class LoginForm(forms.Form):
username = forms.EmailField(label='Email')
password = forms.CharField(label='Mot de passe', widget=forms.PasswordInput)
About the cleaned data i log the data i get for debug purpose and they're right.
EDIT2: My User Model
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True, verbose_name='e-mail')
fname = models.CharField(max_length=64, verbose_name='first name', null=False, blank=False)
lname = models.CharField(max_length=64, verbose_name='last name', null=False, blank=False)
login = models.CharField(max_length=64, null=True, blank=True, verbose_name="login")
promo = models.CharField(max_length=64, null=True, blank=True, verbose_name="promotion")
exte = models.BooleanField(default=False, verbose_name="externe")
joined = models.DateTimeField(auto_now_add=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
is_active = models.BooleanField(default=True, verbose_name='active user')
is_staff = models.BooleanField(default=False, verbose_name='admin user')
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fname', 'lname']
def get_full_name(self):
return "{0} {1}".format(self.fname, self.lname)
def get_short_name(self):
return self.lname
def __str__(self):
return self.get_full_name()
def has_perm(self, perm, obj=None):
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
# Simplest possible answer: Yes, always
return True
You have an indentation problem on your form. Your save method (as well as the clean_pass2 method) are wrongly indented inside the inner Meta class, so it won't be seen by the form itself. This means that set_password won't be called when you create the user, so the password will not be hashed.
Move those methods one indent to the left.